Jump to content
kongondo

Module: Jquery File Upload

Recommended Posts

JqueryFileUpload
 
This module is a ProcessWire implementation of the awesome Blueimp jQuery File Upload plugin.  Server-side, the module provides a custom uploads' handler enabling you to perform various tasks with ease. The module is an interface of the feature-rich Ajax File Uploads widget provided by the jQuery File Upload plugin.
 
The module is completely customisable and can be used both in the front- and backend (e.g. in a third-party module). 
 
Please read the README  carefully and completely before using the module
 
Release Status: Stable
Module Download: http://modules.processwire.com/modules/jquery-file-upload/
Issues tracker Project page: GitHub
 
Security
The module has been written with security in mind and makes no assumptions about any client-side validation. Instead, the module provides robust server-side validation of uploaded files. Server-side, no Ajax requests are honoured unless specifically set via configurable options server-side. This means that client-side requests to upload, delete and list files are not executed unless allowed server-side. By default, files are uploaded to a non-web-accessible (system) folder and files previously uploaded on the server are not sent back for display unless that setting is enabled. However, developers are still strongly advised to implement any other feasible measures to guard against malicious uploads, especially if allowing frontend uploading. For instance, developers can use native ProcessWire checks to limit access to the widget (e.g. only allowing uploads by registered/logged-in users).
 
Demo
A short video demo can be found here (and below :-))(CSS is WIP!  :-)). In the backend, you can see it in action within the (upcoming) module Media Manager
 
Features

  •  Fast Ajax uploads.
  •  Client and server-side validation.
  •  Client-side image resizing (highly configurable options).
  •  Beautiful touch-responsive image gallery preview.
  •  Audio and video previews pre-upload.
  • Chunked and resumable file uploads (currently client-side only; server-side handling planned).
  •  Drag and drop support.
  •  Copy and paste support (Google Chrome only).
  •  Progress bars.
  •  Cross-domain uploads.
  •  Single or multiple uploads.
  •  Delete uploaded files.

Documentation
On GitHub. Have a look at the long list of available options.
 
License
Released under the MIT license
 
@Credits: Sebastian Tschan
@Thanks: Pete and BernhardB for the idea.
 
Please test and provide feedback. Thanks!
 

  • Like 32

Share this post


Link to post
Share on other sites

Man - you aren't just on fire at the moment, you are ablaze :)

Nice work - I have used Blueimp on some other projects pre-PW and loved it, so thank you!

  • Like 1

Share this post


Link to post
Share on other sites

Your timing is impeccable - just what I need today! :)

Share this post


Link to post
Share on other sites

Man - you aren't just on fire at the moment, you are ablaze :)

Nice work - I have used Blueimp on some other projects pre-PW and loved it, so thank you!

3 AM blues!

  • Like 1

Share this post


Link to post
Share on other sites

I finally made it to work on frontend - didn't notice 'disableUploads' => true in the example ... should read more carefully

Share this post


Link to post
Share on other sites

Testing again on IIS with PW3. After upload I don't have access to uploaded files. I get HTTP 500.50 error along with 0x80070005 and that is (from my experience) permission issue. I'm assuming (didn't look at your sources) that files are uploaded to temp directory (PHP's upload_tmp_dir?) and then moved/renamed to the final destination at /site/assets/files/jqfu/files. In the process of moving the files, permissions of the files are inherited from the temp directory and those are not sufficient for the web server. Would you consider using $config->$uploadTmpDir instead of PHP's upload_tmp_dir?

Edit: I see you are using WireUpload class so I'll have to take a closer look into WireUpload.php...

Edited by matjazp

Share this post


Link to post
Share on other sites

PHP stores the uploaded file in the folder determined by upload_tmp_dir directive in php.ini. By default this is C:\Windows\Temp directory. After the uploaded file is stored to the upload_tmp_dir, ProcessWire will then move/rename the file to the final destination directory and that doesn’t inherit destination directory’s permissions. There are multiple options on how to make it work:
 
a.) Change the permissions on the windows temp folder giving IUSR and IIS_IUSRS  write/modify
b.) Change the path of the upload_tmp_dir in the php.ini file to a folder with appropriate permissions
c.) Change the way WireUpload works so that it copy the file, not rename/move it.
 
I didn't have upload problems in admin, because I used $config->$uploadTmpDir pointing to the /site/assets/uploads folder (created by me). This folder is used in WireUpload.php with ajax uploading (using $_SERVER['HTTP_X_FILENAME']). Since /site/assets/uploads folder inherits /site/assets folder permissions, moving/renaming the file is not the problem. When uploading using PHP's $_FILES global variable, $config->$uploadTmpDir is not used and files are uploaded to the folder set up by upload_tmp_dir directive.

As copying in slower than renaming, I'm not sure if this is the right solution (file WireUpload.php in function saveUpload):

$success = move_uploaded_file($tmp_name, $destination);

to:

$success = is_uploaded_file($tmp_name);
if($success) $success = @copy($tmp_name, $destination);
if(is_file($tmp_name)) @unlink($tmp_name);

Share this post


Link to post
Share on other sites

Good forensics. If it's a WireUpload.php issue then you can put in a request with @Ryan to hear his thoughts? Meanwhile, you can always use a custom uploads handler in conjunction with the other methods that come with the module, e.g. getResponse() which calls the crucial validation methods.

Share this post


Link to post
Share on other sites

I've written the issue on GitHub to hear Ryan's thoughts. I'm not good enough in PHP or PW internals and don't know when ajax upload is used. In "ajax mode" uploaded file is read from php://input and then created at the $config->$uploadTmpDir (if set) folder. In "nonajax mode" $config->$uploadTmpDir is not used - files are uploaded to the folder set up by upload_tmp_dir directive in php.ini It would be ideal if "nonajax upload" would store files in $config->$uploadTmpDir to... Is this possible? Sorry for dumb questions...

  • Like 1

Share this post


Link to post
Share on other sites

Do you have the demo without/or different music? The German GEMA and SME had YouTube blocking the video for Germany.  :'(

  • Like 1

Share this post


Link to post
Share on other sites

For a minute there I thought you were kidding. Never heard of this German GEMA & SME thing. I have just quickly read up about it. Well, I could try upload the video to Vimeo (would that work?) or you could do me a favour and watch the YT one behind a proxy :) ...that's not illegal, or is it?

Edit: There's also the 'original' demo at Blueimp

  • Like 1

Share this post


Link to post
Share on other sites

For a minute there I thought you were kidding. Never heard of this German GEMA & SME thing. I have just quickly read up about it. Well, I could try upload the video to Vimeo (would that work?) or you could do me a favour and watch the YT one behind a proxy :) ...that's not illegal, or is it?

I assume this will not work with a simple proxy as it is not that easy to trick google / youtube.

Share this post


Link to post
Share on other sites

I assume this will not work with a simple proxy as it is not that easy to trick google / youtube.

:ph34r:

...I have started the 'slow' upload to vimeo... :'(.... :lol:

  • Like 1

Share this post


Link to post
Share on other sites

Here's the vimeo version. Cannot get 1080p quality unless you are on the paid plans, but its viewable. I don't think am uploading to vimeo again...this was the first and last time. It takes forever and they restrict the quality, tsk.  :-)

  • Like 1

Share this post


Link to post
Share on other sites

It is an awesome video, so, also with music. Have had a nice looking. Thanks man!

Will also try the module in the next time.

  • Like 1

Share this post


Link to post
Share on other sites

Will also try the module in the next time.

Thanks. Will appreciate your professional opinion especially regarding the client-side-image resizing

  • Like 1

Share this post


Link to post
Share on other sites

Firstly - Kongondo - thanks for another great module.

I have been working on this all day and I have the form working well on the frontend, I can upload images and other files and I can see the upload progress etc on screen which is great and exactly what I've been looking for.

Where I've hit a brick wall for the last 3-4 hours though is I can't work out how to attach this to a field on one of my templates.  I have a template where I want to have a field which will allow users to upload images or files via the frontend. I have some other fields in the template too (normal text fields for description etc) and I have had those working for a long time - what I can't work out is how do I take the files uploaded via this jQuery module and add them to the files field in my template???

Any help gratefully received..

Share this post


Link to post
Share on other sites

Hi @Hantsweb,

Glad you like the module.

Technically, you can't 'attach' the module to a field in one of your templates :-). But I think I get what you are saying. You want uploaded files to be added to a field on some page(s). Before I dive into an answer, I hope in your upload implementation you've remembered to...'never to trust your users',...especially those who are allowed to add things to pages and whether what they've uploaded is immediately viewable on the frontend :-). Yes, the module does very thorough validation and will only upload what you've allowed to be uploaded but its always good to double check.

Below are links to some code I've previously posted that will be of help. What is your workflow? Are user uploads immediately added to a page? Are there unique pages for each user? Are compressed files (zip) in play? Whatever the answer to these questions, the basics are the same:

  1. Upload files to your server to a specified temporary folder(s). During the process validate the files: JqueryFileUpload
  2. Iterate over the folder with the uploads: I always use PHP SPL class for this, e.g. RecursiveDirectoryIterator
  3. In each iteration, add valid files to specified pages (if those pages are not being created by the uploads): Use ProcessWire for this
  4. Delete uploads in the temporary folder

Example code:

https://processwire.com/talk/topic/10815-mass-create-pages-or-mass-upload-images-and-thus-create-pages/?p=101791

https://processwire.com/talk/topic/8416-importing-many-pictures-in-a-page/

If you are adding to files to pages directly after they've been uploaded, you will want to listen to Ajax requests sent by JqueryFileUpload like so:

if ($this->config->ajax) {
  // you code here for iteration, creating and/or adding files to pages

}

Let us know if you hit another brick wall :-)

  • Like 1

Share this post


Link to post
Share on other sites

hi kongondo,

if i get you right, this module is intended to be used on frontend, isn't it? in the demo, though, it is used in backend with your media manager. would it be hard to get some kind of replacement of a standard image field directly in the backend? :)

Share this post


Link to post
Share on other sites

hi kongondo,

if i get you right, this module is intended to be used on frontend, isn't it? in the demo, though, it is used in backend with your media manager. would it be hard to get some kind of replacement of a standard image field directly in the backend? :)

:huh:  :huh:   :o  :o  :undecided:   :undecided:  

The module is completely customisable and can be used both in the front- and backend (e.g. in a third-party module).

In the video 0.00 - 4.25 Frontend (check the URL); 4.25 to end Backend (MediaManager)

:-)

As for your question about image replacement: I think it would be easiest to either extend FieldtypeFile or modify FieldtypeImage as a new module (and/or their related Inputfields - am not sure). What exactly are you after? I ask because I know there are some cool changes coming to the 'standard image field' and those might just meet your needs.

Edited by kongondo
  • Like 1

Share this post


Link to post
Share on other sites

thank you and sorry for not reading carefully enough  :-[

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Gadgetto
      SnipWire - Snipcart integration for ProcessWire
      Snipcart is a powerful 3rd party, developer-first HTML/JavaScript shopping cart platform. SnipWire is the missing link between Snipcart and the content management framework ProcessWire.
      With SnipWire, you can quickly turn any ProcessWire site into a Snipcart online shop. The SnipWire plugin helps you to get your store up and running in no time. Detailed knowledge of the Snipcart system is not required.
      SnipWire is free and open source licensed under Mozilla Public License 2.0! A lot of work and effort has gone into development. It would be nice if you could donate an amount to support further development:

      Status update links (inside this thread) for SnipWire development
      2020-07-03 -- SnipWire 0.8.7 (beta) released! Fixes some small bugs and adds an indicator for TEST mode 2020-04-06 -- SnipWire 0.8.6 (beta) released! Adds support for Snipcart subscriptions and also fixes some problems 2020-03-21 -- SnipWire 0.8.5 (beta) released! Improves SnipWires webhooks interface and provides some other fixes and additions 2020-03-03 -- SnipWire 0.8.4 (beta) released! Improves compatibility for Windows based Systems. 2020-03-01 -- SnipWire 0.8.3 (beta) released! The installation and uninstallation process has been heavily revised. 2020-02-08 -- SnipWire 0.8.2 (beta) released! Added a feature to change the cart and catalogue currency by GET, POST or SESSION param 2020-02-03 -- SnipWire 0.8.1 (beta) released! All custom classes moved into their own namespaces. 2020-02-01 -- SnipWire is now available via ProcessWire's module directory! 2020-01-30 -- SnipWire 0.8.0 (beta) first public release! (module just submitted to the PW modules directory) 2020-01-28 -- added Custom Order Fields feature (first SnipWire release version is near!) 2020-01-21 -- Snipcart v3 - when will the new cart system be implemented? 2020-01-19 -- integrated taxes provider finished (+ very flexible shipping taxes handling) 2020-01-14 -- new date range picker, discount editor, order notifiactions, order statuses, and more ... 2019-11-15 -- orders filter, order details, download + resend invoices, refunds 2019-10-18 -- list filters, REST API improvements, new docs platform, and more ... 2019-08-08 -- dashboard interface, currency selector, managing Orders, Customers and Products, Added a WireTabs, refinded caching behavior 2019-06-15 -- taxes provider, shop templates update, multiCURL implementation, and more ... 2019-06-02 -- FieldtypeSnipWireTaxSelector 2019-05-25 -- SnipWire will be free and open source Plugin Key Features
      Fast and simple store setup Full integration of the Snipcart dashboard into the ProcessWire backend (no need to leave the ProcessWire admin area) Browse and manage orders, customers, discounts, abandoned carts, and more Multi currency support Custom order and cart fields Process refunds and send customer notifications from within the ProcessWire backend Process Abandoned Carts + sending messages to customers from within the ProcessWire backend Complete Snipcart webhooks integration (all events are hookable via ProcessWire hooks) Integrated taxes provider (which is more flexible then Snipcart own provider) Useful Links
      SnipWire in PW modules directory SnipWire Docs (please note that the documentation is a work in progress) SnipWire @GitHub (feature requests and suggestions for improvement are welcome - I also accept pull requests) Snipcart Website  

       
      ---- INITIAL POST FROM 2019-05-25 ----
       
    • By Sten
      Hello
      Till now I hacked something with the twig template but it works no more with new PW versions so I look forward to create a module. I am working on a site in multiple languages : French, English, Italian, German, Spanish, Portuguese, Hebrew, Russian. The new posts are entered in any language with a field for language. Till now, I got twig files to get the translations with constants defined for each part of the pages.
      So I'd like to create a module to include theses files added according to the url /fr/en/...
      Have you some observations to do before I begin about the direction to take ?
      Thank you
    • By ukyo
      Mystique Module for ProcessWire CMS/CMF
      Github repo : https://github.com/trk/Mystique
      Mystique module allow you to create dynamic fields and store dynamic fields data on database by using a config file.
      Requirements
      ProcessWire 3.0 or newer PHP 7.0 or newer FieldtypeMystique InputfieldMystique Installation
      Install the module from the modules directory:
      Via Composer:
      composer require trk/mystique Via git clone:
      cd your-processwire-project-folder/ cd site/modules/ git clone https://github.com/trk/Mystique.git Module in live reaction with your Mystique config file
      This mean if you remove a field from your config file, field will be removed from edit screen. As you see on youtube video.
      Using Mystique with your module or use different configs path, autoload need to be true for modules
      Default configs path is site/templates/configs/, and your config file name need to start with Mystique. and need to end with .php extension.
      Adding custom path not supporting anymore !
      // Add your custom path inside your module class`init` function, didn't tested outside public function init() { $path = __DIR__ . DIRECTORY_SEPARATOR . 'configs' . DIRECTORY_SEPARATOR; Mystique::add($path); } Mystique module will search site/modules/**/configs/Mystique.*.php and site/templates/Mystique.*.php paths for Mystique config files.
      All config files need to return a PHP ARRAY like examples.
      Usage almost same with ProcessWire Inputfield Api, only difference is set and showIf usage like on example.
      <?php namespace ProcessWire; /** * Resource : testing-mystique */ return [ 'title' => __('Testing Mystique'), 'fields' => [ 'text_field' => [ 'label' => __('You can use short named types'), 'description' => __('In file showIf working like example'), 'notes' => __('Also you can use $input->set() method'), 'type' => 'text', 'showIf' => [ 'another_text' => "=''" ], 'set' => [ 'showCount' => InputfieldText::showCountChars, 'maxlength' => 255 ], 'attr' => [ 'attr-foo' => 'bar', 'attr-bar' => 'foo' ] ], 'another_text' => [ 'label' => __('Another text field (default type is text)') ] ] ]; Example:
      site/templates/configs/Mystique.seo-fields.php <?php namespace ProcessWire; /** * Resource : seo-fields */ return [ 'title' => __('Seo fields'), 'fields' => [ 'window_title' => [ 'label' => __('Window title'), 'type' => Mystique::TEXT, // or InputfieldText 'useLanguages' => true, 'attr' => [ 'placeholder' => __('Enter a window title') ] ], 'navigation_title' => [ 'label' => __('Navigation title'), 'type' => Mystique::TEXT, // or InputfieldText 'useLanguages' => true, 'showIf' => [ 'window_title' => "!=''" ], 'attr' => [ 'placeholder' => __('Enter a navigation title') ] ], 'description' => [ 'label' => __('Description for search engines'), 'type' => Mystique::TEXTAREA, 'useLanguages' => true ], 'page_tpye' => [ 'label' => __('Type'), 'type' => Mystique::SELECT, 'options' => [ 'basic' => __('Basic page'), 'gallery' => __('Gallery'), 'blog' => __('Blog') ] ], 'show_on_nav' => [ 'label' => __('Display this page on navigation'), 'type' => Mystique::CHECKBOX ] ] ]; Searching data on Mystique field is limited. Because, Mystique saving data to database in json format. When you make search for Mystique field, operator not important. Operator will be changed with %= operator.
      Search example
      $navigationPages = pages()->find('my_mystique_field.show_on_nav=1'); $navigationPages = pages()->find('my_mystique_field.page_tpye=gallery');
    • By Robin S
      This is a module I made as an experiment a while ago and never got around to releasing publicly. At the time it was prompted by discussions around using Repeater fields for "page builder" purposes, where the depth feature could possibly be used for elements that would be nested inside other elements. I thought it would be useful to enforce some depth rules and translate the depth data into a multi-dimensional array structure.
      I'm not using this module anywhere myself but maybe it's useful to somebody.
      Repeater Depth Helper
      This module does two things relating to Repeater fields that have the "Item depth" option enabled:
      It enforces some depth rules for Repeater fields on save. Those rules are:
      The first item must have a depth of zero. Each item depth must not be more than one greater than previous item depth. It provides a RepeaterPageArray::getDepthStructure helper method that returns a nested depth structure for a Repeater field value.
      Helper method
      The module adds a RepeaterPageArray::getDepthStructure method that returns a multi-dimensional array where the key is the page ID and the value is an array of nested "child" items, or null if there are no nested children.
      Example

      The module doesn't make any assumptions about how you might want to use the depth structure array, but here is a way you might use it to output a nested unordered list.
      // Output a nested unordered list from a depth structure array function outputNestedList($depth_structure, $repeater_items) { $out = "<ul>"; foreach($depth_structure as $page_id => $nested_children) { $out .= "<li>" . $repeater_items->get("id=$page_id")->title; // Go recursive if there are nested children if(is_array($nested_children)) $out .= outputNestedList($nested_children, $repeater_items); $out .= "</li>"; } $out .= "</ul>"; return $out; } $repeater_items = $page->my_repeater; $depth_structure = $repeater_items->getDepthStructure(); echo outputNestedList($depth_structure, $repeater_items);
       
      https://github.com/Toutouwai/RepeaterDepthHelper
      https://modules.processwire.com/modules/repeater-depth-helper/
    • By MoritzLost
      Cacheable Placeholders
      This module allows you to have pieces of dynamic content inside cached output. This aims to solve the common problem of having a mostly cacheable site, but with pieces of dynamic output here and there.  Consider this simple example, where you want to output a custom greeting to the current user:
      <h1>Good morning, <?= ucfirst($user->name) ?></h1> This snippet means you can't use the template cache (at least for logged-in users), because each user has a different name. Even if 99% of your output is static, you can only cache the pieces that you know won't include this personal greeting. A more common example would be CSRF tokens for HTML forms - those need to be unique by definition, so you can't cache the form wholesale.
      This module solves this problem by introducing cacheable placeholders - small placeholder tokens that get replaced during every request. The replacement is done inside a Page::render hook so it runs during every request, even if the response is served from the template cache. So you can use something like this:
      <h1>Good morning, {{{greeting}}}</h1> Replacement tokens are defined with a callback function that produces the appropriate output and added to the module through a simple hook:
      // site/ready.php wire()->addHookAfter('CachePlaceholders::getTokens', function (HookEvent $e) { $tokens = $e->return; $tokens['greeting'] = [ 'callback' => function (array $tokenData) { return ucfirst(wire('user')->name); } ]; $e->return = $tokens; }); Tokens can also include parameters that are parsed and passed to the callback function. There are more fully annotated examples and step-by-step instructions in the README on Github!
      Features
      A simple and fast token parser that calls the appropriate callback and runs automatically. Tokens may include multiple named or positional parameters, as well as multi-value parameters. A manual mode that allows you to replace tokens in custom pieces of cached content (useful if you're using the $cache API). Some built-in tokens for common use-cases: CSRF-Tokens, replacing values from superglobals and producing random hexadecimal strings. The token format is completely customizable, all delimiters can be changed to avoid collisions with existing tag parsers or template languages. Links
      Github Repository & documentation Module directory If you are interested in learning more, the README is very extensive, with more usage examples, code samples and usage instructions!
×
×
  • Create New...