diff options
Diffstat (limited to 'sites/all/modules/plupload')
23 files changed, 1587 insertions, 0 deletions
diff --git a/sites/all/modules/plupload/CHANGELOG.txt b/sites/all/modules/plupload/CHANGELOG.txt new file mode 100644 index 000000000..83b9c0705 --- /dev/null +++ b/sites/all/modules/plupload/CHANGELOG.txt @@ -0,0 +1,70 @@ +CHANGELOG for Plupload integration for Drupal 7 + +Plupload integration 7.x-1.7 +================================= +- #2370889 by znerol: Fixed Extra margin on file list due to insufficient specificity of CSS selector. +- #2190007 by slashrsm | hswong3i: Kill Firefox 3.6 check and entire _requirements checks section. +- #2241523 by K. Tadesse, si.mon: Add some more strings to i18n.js. +- #2088143 by hswong3i, Chris Charlton | lsolesen: Add make file so dependencies are downloaded automatically. + +Plupload integration 7.x-1.6 +================================= +- #2171575 by slashrsm | kreatIL: Plupload library not found (version 1.5.8). +- #2098555 by slashrsm: Suggest using .zip instead of .tar.gz. + +Plupload integration 7.x-1.5 +================================= +- by slashrsm: Update README.txt with new download links. +- #2132373 by OnkelTem: Plupload doesn't support international file names. +- #2098555 by slashrsm: Document library v2.0.0 incompatibility. + +Plupload integration 7.x-1.4 +================================= +- #2065927 by vladan.me: Added Plupload events support. +- #2081263 by hgneng: Fixed Check transliteration setting before apply transliteration action. + +Plupload integration 7.x-1.3 +================================= +- #2063161 by mfgering | Amon_Re: Fixed Multi Upload with plupload broken when using Drupal 7.23. + +Plupload integration 7.x-1.2 +================================= +- #1999264 by slashrsm: up_arrow.png and up_arrow_disabled.png are very large. +- #1935256 by Primsi: Fixed When a form has more than one submit button plupload always submits using the first one. + +Plupload integration 7.x-1.1 +================================= +- #1903818 by quicksketch, slashrsm: Fixed Double dollar signs in hook_requirements(). +- #1506642 by MrHaroldA | succinct: Fixed plupload.js issue with Internet Explorer. +- #1814744 by slashrsm, Kevin Hankens: File URI not available to hook_file_validate() implementations. +- #1895328 by larowlan, slashrsm: Fixed Security exploit in plupload external library examples folder. +- #1230632 by -enzo-, slashrsm: Fixed hard-coded file size limits. +- by slashrsm: Fix CodeSniffer errors. +- #1827368 by Kevin Hankens: Fixed Use standard language when validating files. +- #1565898 by slashrsm: Create docs for Plupload element usage in README.txt. +- #1111036 by slashrsm: Blacklist script extensions if 'allow_insecure_uploads' isn't set to TRUE. +- #1426088 by slashrsm: Anonymous User can't upload. + +Plupload integration 7.x-1.0 +================================= +- #1414486 by nbucknor, slashrsm: Improvements of error handling for multiple plupload elements on a single form. + +Plupload integration 7.x-1.0-rc1 +================================== +- by slashrsm: Fix 3 Coder review notices. +- by slashrsm: Removed unnecessary popup caused by previous commit. +- #1414486 by nbucknor, annblack: Allow for Multiple Plupload elements in a form. +- #1461884 by atlea: File uploads larger than php post_max_size broken +- #1445172 by Moloc: Use drupal_unlink() instead unlink() + +Plupload integration 7.x-1.0-beta4 +================================== +- #1230632 by ksenzee: Hard-coded file size limits. +- #1219992 by slashrsm, axe312, Dave Reid: Add support for Drupal native translations. +- #1111054 by George Petsagourakis: Convert plupload_fix_temporary_filename() a private function +- #1316438 by jcfiala, slashrsm: Plupload in AJAX call causes form.submit handler to be added multiple times +- #1300620 by jamiecuthill, ksenzee: Update to 1.5.1.1 because uploading is broken in Firefox 7 +- #1121070 by Moloc: Warning: unlink(...) [function.unlink]: Permission denied in plupload_handle_uploads() +- #1348892 by slashrsm, Moloc: Show library version in status report +- #1267190 by Moloc: Plupload transliteration support for d7 +- #1240654 by Dave Reid: Use a proper namespace for file_uri_to_object(). diff --git a/sites/all/modules/plupload/LICENSE.txt b/sites/all/modules/plupload/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/sites/all/modules/plupload/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey 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 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. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This 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. diff --git a/sites/all/modules/plupload/README.txt b/sites/all/modules/plupload/README.txt new file mode 100644 index 000000000..4e83d0843 --- /dev/null +++ b/sites/all/modules/plupload/README.txt @@ -0,0 +1,89 @@ +This module integrates the Plupload library (available from http://plupload.com) +with Drupal forms. To install the Plupload library: + +1. Download it (version 1.5.1.1 or later) from + https://github.com/moxiecode/plupload/releases Version 2.0.0 + is currently unsupported. Latest 1.x.x version is 1.5.8, which can be + downloaded from https://github.com/moxiecode/plupload/archive/v1.5.8.zip. +2. Unzip it into sites/all/libraries, so that there's a + sites/all/libraries/plupload/js/plupload.full.js file, in addition to the + other files included in the library. +3. Remove "examples" folder from libraries folder as it could constitute a + security risk to your site. See http://drupal.org/node/1895328 and + http://drupal.org/node/1189632 for more info. + +If you would like to use an alternate library location, you can install the +http://drupal.org/project/libraries module and/or add + + $conf['plupload_library_path'] = PATH/TO/PLUPLOAD; + +to your settings.php file. + +At this time, this module only provides a 'plupload' form element type that +other modules can use for providing multiple file upload capability to their +forms. It does not provide any end-user functionality on its own. This may +change, however, as this module evolves. See http://drupal.org/node/880300. + +---=== For developers ===--- + +Plupload from element can be used like this: + +$form['my_element'] = array( + '#type' => 'plupload', + '#title' => t('Upload files'), + '#description' => t('This multi-upload widget uses Plupload library.'), + '#autoupload' => TRUE, + '#autosubmit' => TRUE, + '#submit_element' => '#id-of-your-submit-element', + '#upload_validators' => array( + 'file_validate_extensions' => array('jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'), + 'my_custom_file_validator' => array('some validation criteria'), + ); + '#plupload_settings' => array( + 'runtimes' => 'html5', + 'chunk_size' => '1mb', + ), + '#event_callbacks' => array( + 'FilesAdded' => 'Drupal.mymodule.filesAddedCallback', + 'UploadComplete' => 'Drupal.mymodule.uploadCompleteCallback', + ), +); + +There are few optional properties of this array that have special meaning: + +- #autoupload: set this to TRUE if you want Plupload to start uploading + immediately after files are added. + Defaults to FALSE. + +- #autosubmit: set this to TRUE if you want Plupload to autosubmit + your form after automatic upload has finished. + Defaults to FALSE. + Has to be used in combination with #autoupload. + +- #submit_element: specify which submit element Plupload shall use to submit + the form. Can also be used in combination with #autoupload and #autosubmit. + See: http://drupal.org/node/1935256 + +- #upload_validators - an array of validation function/validation criteria pairs, + that will be passed to file_validate(). + Defaults to: + '#upload_validators' => array( + 'file_validate_extensions' => array('jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'), + ); + +- #plupload_settings - array of settings, that will be passed to Plupload library. + See: http://www.plupload.com/documentation.php + Defaults to: + '#plupload_settings' => array( + 'runtimes' => 'html5,flash,html4', + 'url' => url('plupload-handle-uploads', array('query' => array('plupload_token' => drupal_get_token('plupload-handle-uploads')))), + 'max_file_size' => file_upload_max_size() . 'b', + 'chunk_size' => '1mb', + 'unique_names' => TRUE, + 'flash_swf_url' => file_create_url($library_path . '/js/plupload.flash.swf'), + 'silverlight_xap_url' => file_create_url($library_path . '/js/plupload.silverlight.xap'), + ), + +- #event_callbacks - array of callbacks that will be passed to js. + See full documentation about events in Plupload library: + http://www.plupload.com/example_events.php diff --git a/sites/all/modules/plupload/images/add.png b/sites/all/modules/plupload/images/add.png Binary files differnew file mode 100644 index 000000000..1a2faf656 --- /dev/null +++ b/sites/all/modules/plupload/images/add.png diff --git a/sites/all/modules/plupload/images/backgrounds.gif b/sites/all/modules/plupload/images/backgrounds.gif Binary files differnew file mode 100644 index 000000000..39e33ebc0 --- /dev/null +++ b/sites/all/modules/plupload/images/backgrounds.gif diff --git a/sites/all/modules/plupload/images/buttons-disabled.png b/sites/all/modules/plupload/images/buttons-disabled.png Binary files differnew file mode 100644 index 000000000..afa11af9b --- /dev/null +++ b/sites/all/modules/plupload/images/buttons-disabled.png diff --git a/sites/all/modules/plupload/images/buttons.png b/sites/all/modules/plupload/images/buttons.png Binary files differnew file mode 100644 index 000000000..153e73885 --- /dev/null +++ b/sites/all/modules/plupload/images/buttons.png diff --git a/sites/all/modules/plupload/images/delete.gif b/sites/all/modules/plupload/images/delete.gif Binary files differnew file mode 100644 index 000000000..78ca8b3b4 --- /dev/null +++ b/sites/all/modules/plupload/images/delete.gif diff --git a/sites/all/modules/plupload/images/done.gif b/sites/all/modules/plupload/images/done.gif Binary files differnew file mode 100644 index 000000000..29f3ed7c9 --- /dev/null +++ b/sites/all/modules/plupload/images/done.gif diff --git a/sites/all/modules/plupload/images/error.gif b/sites/all/modules/plupload/images/error.gif Binary files differnew file mode 100644 index 000000000..4682b6300 --- /dev/null +++ b/sites/all/modules/plupload/images/error.gif diff --git a/sites/all/modules/plupload/images/icon-feed.png b/sites/all/modules/plupload/images/icon-feed.png Binary files differnew file mode 100755 index 000000000..9523eaba6 --- /dev/null +++ b/sites/all/modules/plupload/images/icon-feed.png diff --git a/sites/all/modules/plupload/images/throbber.gif b/sites/all/modules/plupload/images/throbber.gif Binary files differnew file mode 100644 index 000000000..4ae8b16a5 --- /dev/null +++ b/sites/all/modules/plupload/images/throbber.gif diff --git a/sites/all/modules/plupload/images/transp50.png b/sites/all/modules/plupload/images/transp50.png Binary files differnew file mode 100644 index 000000000..eb0efe104 --- /dev/null +++ b/sites/all/modules/plupload/images/transp50.png diff --git a/sites/all/modules/plupload/images/up_arrow.png b/sites/all/modules/plupload/images/up_arrow.png Binary files differnew file mode 100644 index 000000000..36e00c249 --- /dev/null +++ b/sites/all/modules/plupload/images/up_arrow.png diff --git a/sites/all/modules/plupload/images/up_arrow_disabled.png b/sites/all/modules/plupload/images/up_arrow_disabled.png Binary files differnew file mode 100644 index 000000000..5233594a8 --- /dev/null +++ b/sites/all/modules/plupload/images/up_arrow_disabled.png diff --git a/sites/all/modules/plupload/images/video-indicator.png b/sites/all/modules/plupload/images/video-indicator.png Binary files differnew file mode 100644 index 000000000..d9eb1361c --- /dev/null +++ b/sites/all/modules/plupload/images/video-indicator.png diff --git a/sites/all/modules/plupload/js/i18n.js b/sites/all/modules/plupload/js/i18n.js new file mode 100644 index 000000000..01f858401 --- /dev/null +++ b/sites/all/modules/plupload/js/i18n.js @@ -0,0 +1,41 @@ +/** + * @file + * Localization file for Plupload's strings. + */ + +// Add translations. +plupload.addI18n({ + "Select files" : Drupal.t("Select files"), + "Add files to the upload queue and click the start button." : Drupal.t("Add files to the upload queue and click the start button."), + "Filename" : Drupal.t("Filename"), + "Status" : Drupal.t("Status"), + "Size" : Drupal.t("Size"), + "Add files" : Drupal.t("Add files"), + "Stop current upload" : Drupal.t("Stop current upload"), + "Start uploading queue" : Drupal.t("Start uploading queue"), + "Uploaded %d/%d files": Drupal.t("Uploaded %d/%d files"), + "N/A" : Drupal.t("N/A"), + "Drag files here." : Drupal.t("Drag files here."), + "File extension error.": Drupal.t("File extension error."), + "File size error.": Drupal.t("File size error."), + "Init error.": Drupal.t("Init error."), + "HTTP Error.": Drupal.t("HTTP Error."), + "Security error.": Drupal.t("Security error."), + "Generic error.": Drupal.t("Generic error."), + "IO error.": Drupal.t("IO error."), + "Start upload" : Drupal.t("Start upload"), + "Stop upload" : Drupal.t("Stop upload"), + "%d files queued" : Drupal.t("%d files queued"), + "Drag files here." : Drupal.t("Drag files here."), + "Start upload" : Drupal.t("Start upload"), + "%d files queued" : Drupal.t("%d files queued"), + "File: %s" : Drupal.t("File: %s"), + "Close" : Drupal.t("Close"), + "Using runtime: " : Drupal.t("Using runtime: "), + "File: %f, size: %s, max file size: %m" : Drupal.t("File: %f, size: %s, max file size: %m"), + "Upload element accepts only %d file(s) at a time. Extra files were stripped." : Drupal.t("Upload element accepts only %d file(s) at a time. Extra files were stripped."), + "Upload URL might be wrong or doesn\"t exist" : Drupal.t("Upload URL might be wrong or doesn\"t exist"), + "Error: File too large: " : Drupal.t("Error: File too large: "), + "Error: Invalid file extension: " : Drupal.t("Error: Invalid file extension: "), + "File count error." : Drupal.t("File count error.") +}); diff --git a/sites/all/modules/plupload/plupload.css b/sites/all/modules/plupload/plupload.css new file mode 100644 index 000000000..a8aae7a6f --- /dev/null +++ b/sites/all/modules/plupload/plupload.css @@ -0,0 +1,204 @@ + +.plupload_button { + display:inline-block; + font:normal 12px sans-serif; + text-decoration:none; + color:#42454a; + margin-right:4px; + outline:0; + -moz-border-radius:3px; + -khtml-border-radius:3px; + -webkit-border-radius:3px; + border-radius:3px; + font-family:"Lucida Grande", Verdana, sans-serif; + border:none; + background:none; + padding:2px 8px 3px 15px; +} + +.plupload_button:hover { + color:#000; + text-decoration:none; +} + +.plupload_disabled,a.plupload_disabled:hover { + cursor:default; + color:#737373; + background:transparent url(images/up_arrow_disabled.png) no-repeat 0 center; + border-color:#c5c5c5; +} + +.plupload_add { + background-position:-181px center; + background:transparent url(images/add.png) no-repeat 0 center; +} + +.plupload_wrapper { + font:normal 11px Verdana,sans-serif; + width:100%; + font-family:"Lucida Grande", Verdana, sans-serif; +} + +.plupload_container { + background:url('images/transp50.png'); +} + +.plupload_container input { + border:1px solid #DDD; + font:normal 11px Verdana,sans-serif; + width:98%; + font-family:"Lucida Grande", Verdana, sans-serif; +} + +.plupload_scroll .plupload_filelist { + height:135px; + overflow-y:scroll; + background:none; + list-style:none; + margin:0; + padding:0; +} + +.plupload_filelist li { + background:#F5F5F5 url('images/backgrounds.gif') repeat-x 0 -156px; + border-bottom:1px solid #DDD; + padding:10px 8px; +} + +.plupload_filelist_header,.plupload_filelist_footer { + background:#DFDFDF; + color:#42454A; + padding:6px 8px; +} + +.plupload_filelist_header { + border-top:1px solid #EEE; + border-bottom:1px solid #CDCDCD; +} + +.plupload_filelist_footer { + border-top:1px solid #FFF; + height:22px; + line-height:20px; + vertical-align:middle; +} + +.plupload_file_name { + float:left; + overflow:hidden; +} + +.plupload_file_status { + color:#777; +} + +.plupload_file_status span { + color:#42454A; +} + +.plupload_file_size,.plupload_file_status,.plupload_progress { + float:right; + width:80px; +} + +.plupload_file_size,.plupload_file_status,.plupload_file_action { + text-align:right; +} + +.plupload_filelist .plupload_file_name { + width:205px; +} + +.plupload_file_action { + float:right; + width:16px; + height:16px; + margin-left:15px; +} + +.plupload_file_action * { + display:none; + width:16px; + height:16px; +} + + li.plupload_uploading { + background:#ECF3DC url('images/backgrounds.gif') repeat-x 0 -238px; +} + + li.plupload_done { + color:#AAA; +} + + li.plupload_delete a { + background:url('images/delete.gif'); +} + + li.plupload_failed a { + background:url('images/error.gif'); + cursor:default; +} + + li.plupload_done a { + background:url('images/done.gif'); + cursor:default; +} + +.plupload_progress,.plupload_upload_status { + display:none; +} + +.plupload_progress_container { + margin-top:3px; + border:1px solid #CCC; + background:#FFF; + padding:1px; +} + +.plupload_progress_bar { + width:0; + height:7px; + background:#CDEB8B; +} + +.plupload_scroll .plupload_filelist_header .plupload_file_action,.plupload_scroll .plupload_filelist_footer .plupload_file_action { + margin-right:17px; +} + +.plupload_clear,.plupload_clearer { + clear:both; +} + +.plupload_clearer,.plupload_progress_bar { + display:block; + font-size:0; + line-height:0; +} + +li.plupload_droptext { + background:transparent; + text-align:center; + vertical-align:middle; + border:0; + line-height:115px; + list-style-type:none; +} + +.plupload { + border:solid 1px #ccc; +} + +.plupload_header { + display:none; +} + +.plupload_button,.plupload_button:hover { + color:#0074bd; + padding-bottom:0; + margin-bottom:0; +} + +.plupload_start,a.plupload_start:hover { + background:transparent url(images/up_arrow.png) no-repeat 0 center; + z-index:100000; +}
\ No newline at end of file diff --git a/sites/all/modules/plupload/plupload.info b/sites/all/modules/plupload/plupload.info new file mode 100644 index 000000000..3aae9daa6 --- /dev/null +++ b/sites/all/modules/plupload/plupload.info @@ -0,0 +1,12 @@ +name = Plupload integration module +description = Provides a plupload element. +files[] = plupload.module +core = 7.x +package = Media + +; Information added by Drupal.org packaging script on 2014-11-07 +version = "7.x-1.7" +core = "7.x" +project = "plupload" +datestamp = "1415390716" + diff --git a/sites/all/modules/plupload/plupload.install b/sites/all/modules/plupload/plupload.install new file mode 100644 index 000000000..85cddda6a --- /dev/null +++ b/sites/all/modules/plupload/plupload.install @@ -0,0 +1,122 @@ +<?php + +/** + * @file + * Install, update and uninstall functions for the Plupload module. + */ + +/** + * Implements hook_requirements(). + */ +function plupload_requirements($phase) { + $requirements = array(); + $t = get_t(); + + if ($phase == 'runtime') { + $requirements['plupload'] = array( + 'title' => $t('Plupload library'), + 'value' => $t('Unknown'), + ); + $requirements['plupload']['severity'] = REQUIREMENT_OK; + $libraries = plupload_library(); + $library = $libraries['plupload']; + + // Check if Plupload library exists. Try to determine it's version + // if it does. + if (!_plupload_requirements_installed()) { + $message = 'The <a href="@url">@title</a> library (version @version or higher) is not installed.'; + $args = array( + '@title' => $library['title'], + '@url' => url($library['website']), + '@version' => $library['version'], + ); + + $requirements['plupload']['description'] = $t($message, $args); + $requirements['plupload']['severity'] = REQUIREMENT_ERROR; + } + elseif (($installed_version = _plupload_requirements_version()) === NULL) { + $requirements['plupload']['description'] = $t('Plupload version could not be determined.'); + $requirements['plupload']['severity'] = REQUIREMENT_INFO; + } + elseif (!version_compare($library['version'], $installed_version, '<=')) { + $requirements['plupload']['description'] = $t('Plupload @version or higher is required.', array('@version' => $library['version'])); + $requirements['plupload']['severity'] = REQUIREMENT_INFO; + } + + $requirements['plupload']['value'] = empty($installed_version) ? $t('Not found') : $installed_version; + + if (file_exists(_plupload_library_path() . '/examples/upload.php')) { + $requirements['plupload_examples'] = array( + 'title' => $t('Plupload example folder'), + 'value' => $t('Example folder found'), + 'description' => $t('Plupload library contains example files, these could constitute a security risk to your site as per <a href="!url">PSA-2011-02</a>. Please remove the !path folder immediately.', array( + '!url' => 'http://drupal.org/node/1189632', + '!path' => _plupload_library_path() . '/examples' + )), + 'severity' => REQUIREMENT_ERROR + ); + } + } + + return $requirements; +} + +/** + * Checks wether Plupload library exists or not. + * + * @return boolean + * TRUE if plupload library installed, FALSE otherwise. + */ +function _plupload_requirements_installed() { + $libraries = plupload_library(); + $library = $libraries['plupload']; + + // We grab the first file and check if it exists. + $testfile = key($library['js']); + if (!file_exists($testfile)) { + return FALSE; + } + + return TRUE; +} + +/** + * Returns the version of the installed plupload library. + * + * @return string + * The version of installed Plupload or NULL if unable to detect version. + */ +function _plupload_requirements_version() { + $library_path = _plupload_library_path(); + $jspath = $library_path . '/js/plupload.js'; + + // Read contents of Plupload's javascript file. + $configcontents = @file_get_contents($jspath); + if (!$configcontents) { + return NULL; + } + + // Search for version string using a regular expression. + $matches = array(); + if (preg_match('#VERSION:\"(\d+[\.\d+]*)\"#', $configcontents, $matches)) { + return $matches[1]; + } + + // After 1.5.8 Plupload stopped adding version string to .js file. Let's check + // first line of changelog.txt. + $library_path = _plupload_library_path(); + $clpath = $library_path . '/changelog.txt'; + + $configcontents = @file_get_contents($clpath); + if (!$configcontents) { + return NULL; + } + + $lines = explode("\n", $configcontents); + + if (preg_match('#^Version (\d+[\.\d+]*)#', $lines[0], $matches)) { + return $matches[1]; + } + + return NULL; +} diff --git a/sites/all/modules/plupload/plupload.js b/sites/all/modules/plupload/plupload.js new file mode 100644 index 000000000..91a5c6b21 --- /dev/null +++ b/sites/all/modules/plupload/plupload.js @@ -0,0 +1,178 @@ +(function($) { + +Drupal.plupload = Drupal.plupload || {}; +// Add Plupload events for autoupload and autosubmit. +Drupal.plupload.filesAddedCallback = function (up, files) { + setTimeout(function(){up.start()}, 100); +}; +Drupal.plupload.uploadCompleteCallback = function(up, files) { + var $this = $("#"+up.settings.container); + // If there is submit_element trigger it. + var submit_element = window.Drupal.settings.plupload[$this.attr('id')].submit_element; + if (submit_element) { + $(submit_element).click(); + } + // Otherwise submit default form. + else { + var $form = $this.parents('form'); + $($form[0]).submit(); + } +}; +/** + * Attaches the Plupload behavior to each Plupload form element. + */ +Drupal.behaviors.plupload = { + attach: function (context, settings) { + $(".plupload-element", context).once('plupload-init', function () { + var $this = $(this); + + // Merge the default settings and the element settings to get a full + // settings object to pass to the Plupload library for this element. + var id = $this.attr('id'); + var defaultSettings = settings.plupload['_default'] ? settings.plupload['_default'] : {}; + var elementSettings = (id && settings.plupload[id]) ? settings.plupload[id] : {}; + var pluploadSettings = $.extend({}, defaultSettings, elementSettings); + + // Process Plupload events. + if (elementSettings['init'] || false) { + if (!pluploadSettings.init) { + pluploadSettings.init = {}; + } + for (var key in elementSettings['init']) { + var callback = elementSettings['init'][key].split('.'); + var fn = window; + for (var j = 0; j < callback.length; j++) { + fn = fn[callback[j]]; + } + if (typeof fn === 'function') { + pluploadSettings.init[key] = fn; + } + } + } + // Initialize Plupload for this element. + $this.pluploadQueue(pluploadSettings); + + }); + } +}; + + /** + * Attaches the Plupload behavior to each Plupload form element. + */ +Drupal.behaviors.pluploadform = { + attach: function(context, settings) { + $('form', context).once('plupload-form', function() { + if (0 < $(this).find('.plupload-element').length) { + var $form = $(this); + var originalFormAttributes = { + 'method': $form.attr('method'), + 'enctype': $form.attr('enctype'), + 'action': $form.attr('action'), + 'target': $form.attr('target') + }; + + $(this).submit(function(e) { + var completedPluploaders = 0; + var totalPluploaders = $(this).find('.plupload-element').length; + var errors = ''; + + $(this).find('.plupload-element').each( function(index){ + var uploader = $(this).pluploadQueue(); + + var id = $(this).attr('id'); + var defaultSettings = settings.plupload['_default'] ? settings.plupload['_default'] : {}; + var elementSettings = (id && settings.plupload[id]) ? settings.plupload[id] : {}; + var pluploadSettings = $.extend({}, defaultSettings, elementSettings); + + //Only allow the submit to proceed if there are files and they've all + //completed uploading. + //TODO: Implement a setting for whether the field is required, rather + //than assuming that all are. + if (uploader.state == plupload.STARTED) { + errors += Drupal.t("Please wait while your files are being uploaded."); + } + else if (uploader.files.length == 0 && !pluploadSettings.required) { + completedPluploaders++; + } + + else if (uploader.files.length == 0) { + errors += Drupal.t("@index: You must upload at least one file.\n",{'@index': (index + 1)}); + } + + else if (uploader.files.length > 0 && uploader.total.uploaded == uploader.files.length) { + completedPluploaders++; + } + + else { + var stateChangedHandler = function() { + if (uploader.total.uploaded == uploader.files.length) { + uploader.unbind('StateChanged', stateChangedHandler); + completedPluploaders++; + if (completedPluploaders == totalPluploaders ) { + //Plupload's html4 runtime has a bug where it changes the + //attributes of the form to handle the file upload, but then + //fails to change them back after the upload is finished. + for (var attr in originalFormAttributes) { + $form.attr(attr, originalFormAttributes[attr]); + } + // Click a specific element if one is specified. + if (settings.plupload[id].submit_element) { + $(settings.plupload[id].submit_element).click(); + } + else { + $form.submit(); + } + return true; + } + } + }; + uploader.bind('StateChanged', stateChangedHandler); + uploader.start(); + } + + }); + if (completedPluploaders == totalPluploaders) { + //Plupload's html4 runtime has a bug where it changes the + //attributes of the form to handle the file upload, but then + //fails to change them back after the upload is finished. + for (var attr in originalFormAttributes) { + $form.attr(attr, originalFormAttributes[attr]); + } + return true; + } + else if (0 < errors.length){ + alert(errors); + } + + return false; + }); + } + }); + } +}; + + +/** + * Helper function to compare version strings. + * + * Returns one of: + * - A negative integer if a < b. + * - A positive integer if a > b. + * - 0 if a == b. + */ +Drupal.plupload.compareVersions = function (a, b) { + a = a.split('.'); + b = b.split('.'); + // Return the most significant difference, if there is one. + for (var i=0; i < Math.min(a.length, b.length); i++) { + var compare = parseInt(a[i]) - parseInt(b[i]); + if (compare != 0) { + return compare; + } + } + // If the common parts of the two version strings are equal, the greater + // version number is the one with the most sections. + return a.length - b.length; +} + +})(jQuery); diff --git a/sites/all/modules/plupload/plupload.make b/sites/all/modules/plupload/plupload.make new file mode 100644 index 000000000..1c6463103 --- /dev/null +++ b/sites/all/modules/plupload/plupload.make @@ -0,0 +1,9 @@ +api = 2 +core = 7.x + +; Libraries +libraries[plupload][directory_name] = plupload +libraries[plupload][download][type] = file +libraries[plupload][download][url] = https://github.com/moxiecode/plupload/archive/v1.5.8.zip +libraries[plupload][patch][1903850] = https://drupal.org/files/issues/plupload-1_5_8-rm_examples-1903850-16.patch +libraries[plupload][type] = library diff --git a/sites/all/modules/plupload/plupload.module b/sites/all/modules/plupload/plupload.module new file mode 100644 index 000000000..e187f7a57 --- /dev/null +++ b/sites/all/modules/plupload/plupload.module @@ -0,0 +1,523 @@ +<?php + +/** + * @file + * Implementation of plupload.module. + */ + +/** + * Implements hook_menu(). + */ +function plupload_menu() { + $items['plupload-handle-uploads'] = array( + 'title' => 'Handles uploads', + 'page callback' => 'plupload_handle_uploads', + 'type' => MENU_CALLBACK, + 'access callback' => 'plupload_upload_access', + 'access arguments' => array('access content'), + ); + $items['plupload-test'] = array( + 'title' => 'Test Plupload', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('plupload_test'), + // @todo: change this to something appropriate, not sure what. + 'access arguments' => array('Administer site configuration'), + 'type' => MENU_CALLBACK, + ); + return $items; +} + +/** + * Verifies the token for this request. + */ +function plupload_upload_access() { + foreach (func_get_args() as $permission) { + if (!user_access($permission)) { + return FALSE; + } + } + return !empty($_REQUEST['plupload_token']) && drupal_valid_token($_REQUEST['plupload_token'], 'plupload-handle-uploads'); +} + +/** + * Form callback function for test page visible at URL "plupload-test". + */ +function plupload_test($form, &$form_state) { + $form['pud'] = array( + '#type' => 'plupload', + '#title' => 'Plupload', + // '#validators' => array(...); + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Submit', + ); + + return $form; +} + +/** + * Submit callback for plupload_test form. + */ +function plupload_test_submit($form, &$form_state) { + $saved_files = array(); + $scheme = variable_get('file_default_scheme', 'public') . '://'; + // We can't use file_save_upload() because of + // http://www.jacobsingh.name/content/tight-coupling-no-not + // file_uri_to_object(); + foreach ($form_state['values']['pud'] as $uploaded_file) { + if ($uploaded_file['status'] == 'done') { + $source = $uploaded_file['tmppath']; + $destination = file_stream_wrapper_uri_normalize($scheme . $uploaded_file['name']); + // Rename it to its original name, and put it in its final home. + // Note - not using file_move here because if we call file_get_mime + // (in file_uri_to_object) while it has a .tmp extension, it horks. + $destination = file_unmanaged_move($source, $destination, FILE_EXISTS_RENAME); + $file = plupload_file_uri_to_object($destination); + file_save($file); + $saved_files[] = $file; + } + else { + // @todo: move this to element validate or something and clean up t(). + form_set_error('pud', "Upload of {$uploaded_file['name']} failed"); + } + } +} + +/** + * Implements hook_element_info(). + */ +function plupload_element_info() { + $types = array(); + $module_path = drupal_get_path('module', 'plupload'); + $types['plupload'] = array( + '#input' => TRUE, + '#attributes' => array('class' => array('plupload-element')), + // @todo + // '#element_validate' => array('file_managed_file_validate'), + '#theme_wrappers' => array('form_element'), + '#theme' => 'container', + '#value_callback' => 'plupload_element_value', + '#attached' => array( + 'library' => array(array('plupload', 'plupload')), + 'js' => array($module_path . '/plupload.js'), + 'css' => array($module_path . '/plupload.css'), + ), + '#process' => array('plupload_element_process'), + '#element_validate' => array('plupload_element_validate'), + '#pre_render' => array('plupload_element_pre_render'), + ); + return $types; +} + +/** + * Validate callback for plupload form element. + */ +function plupload_element_value(&$element, $input = FALSE, $form_state = NULL) { + $id = $element['#id']; + // If a unique identifier added with '--', we need to exclude it + if(preg_match('/(.*)(--[0-9]+)$/', $id, $reg)) { + $id = $reg[1]; + } + $files = array(); + foreach ($form_state['input'] as $key => $value) { + if (preg_match('/' . $id . '_([0-9]+)_(.*)/', $key, $reg)) { + $i = $reg[1]; + $key = $reg[2]; + + // Only add the keys we expect. + if (!in_array($key, array('tmpname', 'name', 'status'))) { + continue; + } + + // Munge the submitted file names for security. + // + // Similar munging is normally done by file_save_upload(), but submit + // handlers for forms containing plupload elements can't use + // file_save_upload(), for reasons discussed in plupload_test_submit(). + // So we have to do this for them. + // + // Note that we do the munging here in the value callback function + // (rather than during form validation or elsewhere) because we want to + // actually modify the submitted values rather than reject them outright; + // file names that require munging can be innocent and do not necessarily + // indicate an attempted exploit. Actual validation of the file names is + // performed later, in plupload_element_validate(). + if (in_array($key, array('tmpname', 'name'))) { + // Find the whitelist of extensions to use when munging. If there are + // none, we'll be adding default ones in plupload_element_process(), so + // use those here. + if (isset($element['#upload_validators']['file_validate_extensions'][0])) { + $extensions = $element['#upload_validators']['file_validate_extensions'][0]; + } + else { + $validators = _plupload_default_upload_validators(); + $extensions = $validators['file_validate_extensions'][0]; + } + $value = file_munge_filename($value, $extensions, FALSE); + // To prevent directory traversal issues, make sure the file name does + // not contain any directory components in it. (This more properly + // belongs in the form validation step, but it's simpler to do here so + // that we don't have to deal with the temporary file names during form + // validation and can just focus on the final file name.) + // + // This step is necessary since this module allows a large amount of + // flexibility in where its files are placed (for example, they could + // be intended for public://subdirectory rather than public://, and we + // don't want an attacker to be able to get them back into the top + // level of public:// in that case). + $value = rtrim(drupal_basename($value), '.'); + + + // Based on the same feture from file_save_upload(). + if (!variable_get('allow_insecure_uploads', 0) && preg_match('/\.(php|pl|py|cgi|asp|js)(\.|$)/i', $value) && (substr($value, -4) != '.txt')) { + $value .= '.txt'; + + // The .txt extension may not be in the allowed list of extensions. + // We have to add it here or else the file upload will fail. + if (!empty($extensions)) { + $element['#upload_validators']['file_validate_extensions'][0] .= ' txt'; + drupal_set_message(t('For security reasons, your upload has been renamed to %filename.', array('%filename' => $value))); + } + } + } + + // The temporary file name has to be processed further so it matches what + // was used when the file was written; see plupload_handle_uploads(). + if ($key == 'tmpname') { + $value = _plupload_fix_temporary_filename($value); + // We also define an extra key 'tmppath' which is useful so that submit + // handlers do not need to know which directory plupload stored the + // temporary files in before trying to copy them. + $files[$i]['tmppath'] = variable_get('plupload_temporary_uri', 'temporary://') . $value; + } + elseif ($key == 'name') { + if (module_exists('transliteration') && variable_get('transliteration_file_uploads', TRUE)) { + $value = transliteration_clean_filename($value); + } + } + + // Store the final value in the array we will return. + $files[$i][$key] = $value; + } + } + return $files; +} + +/** + * Process callback (#process) for plupload form element. + */ +function plupload_element_process($element) { + // Start session if not there yet. We need session if we want security + // tokens to work properly. + if (!drupal_session_started()) { + drupal_session_start(); + } + + if (!isset($element['#upload_validators'])) { + $element['#upload_validators'] = array(); + } + $element['#upload_validators'] += _plupload_default_upload_validators(); + return $element; +} + +/** + * Element validation handler for a Plupload element. + */ +function plupload_element_validate($element, &$form_state) { + foreach ($element['#value'] as $file_info) { + // Here we create a $file object for a file that doesn't exist yet, + // because saving the file to its destination is done in a submit handler. + // Using tmp path will give validators access to the actual file on disk and + // filesize information. We manually modify filename and mime to allow + // extension checks. + $file = plupload_file_uri_to_object($file_info['tmppath']); + + $destination = variable_get('file_default_scheme', 'public') . '://' . $file_info['name']; + $destination = file_stream_wrapper_uri_normalize($destination); + $file->filename = drupal_basename($destination); + $file->filemime = file_get_mimetype($destination); + + foreach (file_validate($file, $element['#upload_validators']) as $error_message) { + $message = t('The specified file %name could not be uploaded.', array('%name' => $file->filename)); + form_error($element, $message . ' ' . $error_message); + } + } +} + +/** + * Pre render (#pre_render) callback to attach JS settings for the element. + */ +function plupload_element_pre_render($element) { + $settings = isset($element['#plupload_settings']) ? $element['#plupload_settings'] : array(); + + // The Plupload library supports client-side validation of file extension, so + // pass along the information for it to do that. However, as with all client- + // side validation, this is a UI enhancement only, and not a replacement for + // server-side validation. + if (empty($settings['filters']) && isset($element['#upload_validators']['file_validate_extensions'][0])) { + $settings['filters'][] = array( + // @todo Some runtimes (e.g., flash) require a non-empty title for each + // filter, but I don't know what this title is used for. Seems a shame + // to hard-code it, but what's a good way to avoid that? + 'title' => t('Allowed files'), + 'extensions' => str_replace(' ', ',', $element['#upload_validators']['file_validate_extensions'][0]), + ); + } + // Check for autoupload and autosubmit settings and add appropriate callback. + if (!empty($element['#autoupload'])) { + $settings['init']['FilesAdded'] = 'Drupal.plupload.filesAddedCallback'; + if (!empty($element['#autosubmit'])) { + $settings['init']['UploadComplete'] = 'Drupal.plupload.uploadCompleteCallback'; + } + } + // Add a specific submit element that we want to click if one is specified. + if (!empty($element['#submit_element'])) { + $settings['submit_element'] = $element['#submit_element']; + } + // Check if there are event callbacks and append them to current ones, if any. + if (!empty($element['#event_callbacks'])) { + // array_merge() only accepts parameters of type array. + if (!isset($settings['init'])) { + $settings['init'] = array(); + } + $settings['init'] = array_merge($settings['init'], $element['#event_callbacks']); + } + + if (empty($element['#description'])) { + $element['#description'] = ''; + } + $element['#description'] = theme('file_upload_help', array('description' => $element['#description'], 'upload_validators' => $element['#upload_validators'])); + + $element['#attached']['js'][] = array( + 'type' => 'setting', + 'data' => array('plupload' => array($element['#id'] => $settings)), + ); + + return $element; +} + +/** + * Returns the path to the plupload library. + */ +function _plupload_library_path() { + return variable_get('plupload_library_path', module_exists('libraries') ? libraries_get_path('plupload') : 'sites/all/libraries/plupload'); +} + +/** + * Implements hook_library(). + */ +function plupload_library() { + $library_path = _plupload_library_path(); + $libraries['plupload'] = array( + 'title' => 'Plupload', + 'website' => 'http://www.plupload.com', + 'version' => '1.5.1.1', + 'js' => array( + // @todo - only add gears JS if gears is an enabled runtime. + // $library_path . '/js/gears_init.js' => array(), + $library_path . '/js/jquery.plupload.queue/jquery.plupload.queue.js' => array(), + $library_path . '/js/plupload.full.js' => array(), + 0 => array( + 'type' => 'setting', + 'data' => array( + 'plupload' => array( + // Element-specific settings get keyed by the element id (see + // plupload_element_pre_render()), so put default settings in + // '_default' (Drupal element ids do not have underscores, because + // they have hyphens instead). + '_default' => array( + // @todo Provide a settings page for configuring these. + 'runtimes' => 'html5,flash,html4', + 'url' => url('plupload-handle-uploads', array('query' => array('plupload_token' => drupal_get_token('plupload-handle-uploads')))), + 'max_file_size' => file_upload_max_size() . 'b', + 'chunk_size' => parse_size(ini_get('post_max_size')) . 'b', + 'unique_names' => TRUE, + 'flash_swf_url' => file_create_url($library_path . '/js/plupload.flash.swf'), + 'silverlight_xap_url' => file_create_url($library_path . '/js/plupload.silverlight.xap'), + ), + ), + ), + ), + ), + ); + + if (module_exists('locale')) { + $module_path = drupal_get_path('module', 'plupload'); + $libraries['plupload']['js'][$module_path . '/js/i18n.js'] = array('scope' => 'footer'); + } + + return $libraries; +} + +/** + * Callback that handles and saves uploaded files. + * + * This will respond to the URL on which plupoad library will upload files. + */ +function plupload_handle_uploads() { + // @todo: Implement file_validate_size(); + // Added a variable for this because in HA environments, temporary may need + // to be a shared location for this to work. + $temp_directory = variable_get('plupload_temporary_uri', 'temporary://'); + $writable = file_prepare_directory($temp_directory, FILE_CREATE_DIRECTORY); + if (!$writable) { + die('{"jsonrpc" : "2.0", "error" : {"code": 104, "message": "Failed to open temporary directory."}, "id" : "id"}'); + } + // Try to make sure this is private via htaccess. + file_create_htaccess($temp_directory, TRUE); + + // Chunk it? + $chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0; + + // Get and clean the filename. + $file_name = isset($_REQUEST["name"]) ? $_REQUEST["name"] : ''; + $file_name = _plupload_fix_temporary_filename($file_name); + + // Check the file name for security reasons; it must contain letters, numbers + // and underscores followed by a (single) ".tmp" extension. Since this check + // is more stringent than the one performed in plupload_element_value(), we + // do not need to run the checks performed in that function here. This is + // fortunate, because it would be difficult for us to get the correct list of + // allowed extensions to pass in to file_munge_filename() from this point in + // the code (outside the form API). + if (empty($file_name) || !preg_match('/^\w+\.tmp$/', $file_name)) { + die('{"jsonrpc" : "2.0", "error" : {"code": 105, "message": "Invalid temporary file name."}, "id" : "id"}'); + } + + // Look for the content type header. + if (isset($_SERVER["HTTP_CONTENT_TYPE"])) { + $content_type = $_SERVER["HTTP_CONTENT_TYPE"]; + } + if (isset($_SERVER["CONTENT_TYPE"])) { + $content_type = $_SERVER["CONTENT_TYPE"]; + } + + // Is this a multipart upload?. + if (strpos($content_type, "multipart") !== FALSE) { + if (isset($_FILES['file']['tmp_name']) && is_uploaded_file($_FILES['file']['tmp_name'])) { + // Open temp file. + $out = fopen($temp_directory . $file_name, $chunk == 0 ? "wb" : "ab"); + if ($out) { + // Read binary input stream and append it to temp file. + $in = fopen($_FILES['file']['tmp_name'], "rb"); + + if ($in) { + while ($buff = fread($in, 4096)) { + fwrite($out, $buff); + } + fclose($in); + } + else { + die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}'); + } + + fclose($out); + drupal_unlink($_FILES['file']['tmp_name']); + } + else { + die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); + } + } + else { + die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}'); + } + } + else { + // Open temp file. + $out = fopen($temp_directory . $file_name, $chunk == 0 ? "wb" : "ab"); + if ($out) { + // Read binary input stream and append it to temp file. + $in = fopen("php://input", "rb"); + + if ($in) { + while ($buff = fread($in, 4096)) { + fwrite($out, $buff); + } + fclose($in); + } + else { + die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}'); + } + + fclose($out); + } + else { + die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); + } + } + + // Return JSON-RPC response. + die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}'); +} + +/** + * Returns a file object which can be passed to file_save(). + * + * @param string $uri + * A string containing the URI, path, or filename. + * + * @return boolean + * A file object, or FALSE on error. + * + * @todo Replace with calls to this function with file_uri_to_object() when + * http://drupal.org/node/685818 is fixed in core. + */ +function plupload_file_uri_to_object($uri) { + global $user; + $uri = file_stream_wrapper_uri_normalize($uri); + $wrapper = file_stream_wrapper_get_instance_by_uri($uri); + $file = new StdClass(); + $file->uid = $user->uid; + $file->filename = drupal_basename($uri); + $file->uri = $uri; + $file->filemime = file_get_mimetype($uri); + // This is gagged because some uris will not support it. + $file->filesize = @filesize($uri); + $file->timestamp = REQUEST_TIME; + $file->status = FILE_STATUS_PERMANENT; + return $file; +} + +/** + * Fix the temporary filename provided by the plupload library. + * + * Newer versions of the plupload JavaScript library upload temporary files + * with names that contain the intended final prefix of the uploaded file + * (e.g., ".jpg" or ".png"). Older versions of the plupload library always use + * ".tmp" as the temporary file extension. + * + * We prefer the latter behavior, since although the plupload temporary + * directory where these files live is always expected to be private (and we + * protect it via .htaccess; see plupload_handle_uploads()), in case it ever + * isn't we don't want people to be able to upload files with an arbitrary + * extension into that directory. + * + * This function therefore fixes the plupload temporary filenames so that they + * will always use a ".tmp" extension. + * + * @param string $filename + * The original temporary filename provided by the plupload library. + * + * @return string + * The corrected temporary filename, with a ".tmp" extension replacing the + * original one. + */ +function _plupload_fix_temporary_filename($filename) { + $pos = strpos($filename, '.'); + if ($pos !== FALSE) { + $filename = substr_replace($filename, '.tmp', $pos); + } + return $filename; +} + +/** + * Helper function to add defaults to $element['#upload_validators']. + */ +function _plupload_default_upload_validators() { + return array( + // See file_save_upload() for details. + 'file_validate_extensions' => array('jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'), + ); +} |