-
Posts
120 -
Joined
-
Last visited
Contact Methods
-
Website URL
www.karlvonkarton.be
Profile Information
-
Location
Belgium
-
Interests
Surf - Windsurf - Belgian - Music Producer - Ginger - Creative - Code
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
KarlvonKarton's Achievements
Sr. Member (5/6)
49
Reputation
-
Custom file upload to a folder out of the webroot
KarlvonKarton replied to KarlvonKarton's topic in Modules/Plugins
Indeed, that would be neat. -
I've tried to make a custom file upload module that uploads the files in a folder outside the webroot, but without succes. I tried different approaches, but not getting anywhere... Any ideas how to tackle this? approach 1: <?php namespace ProcessWire; /** * FieldtypeCustomImage * Custom fieldtype that stores images outside the web root. */ class FieldtypeOriginalFile extends FieldtypeFile { public static function getModuleInfo() { return [ 'title' => 'Original Image Field', 'version' => 1, 'summary' => 'An original image field that stores images outside the web root.', 'requires' => ['FieldtypeFile', 'InputfieldOriginalFile'], 'icon' => 'image', ]; } /** * Initialize the module and hook into Pages::saved to move files after the page is saved. */ public function init() { parent::init(); $this->addHookAfter('FieldtypeFile::customizeFilePath', $this, 'customizeFilePath'); $this->addHookAfter('FieldtypeFile::customizeFileUrl', $this, 'customizeFileUrl'); } /** * Customize the file path to store files in a folder named after the page ID. */ public function customizeFilePath(HookEvent $event) { $page = $event->argumentsByName('page'); $field = $event->argumentsByName('field'); $filename = $event->argumentsByName('file'); if ($field->name !== 'originalphoto') return; // Define the base custom storage path $baseCustomPath = '/home/portila/originalphotos/'; // Create a folder named after the page ID $customPath = $baseCustomPath . $page->id . '/'; // Ensure the directory exists if (!is_dir($customPath)) { mkdir($customPath, 0755, true); } // Return the full path to the file $event->return = $customPath . basename($filename); } /** * Customize the URL to serve files from a custom handler. */ public function customizeFileUrl(HookEvent $event) { $page = $event->argumentsByName('page'); $field = $event->argumentsByName('field'); $filename = $event->argumentsByName('file'); if ($field->name !== 'originalphoto') return; // Define the custom URL handler for files $customUrlBase = '/photo-file-handler.php?file='; $filePath = $page->id . '/' . urlencode(basename($filename)); $event->return = $customUrlBase . $filePath; } } Approach 2: <?php namespace ProcessWire; /** * FieldtypeCustomImage * Custom fieldtype that stores images outside the web root. */ class FieldtypeOriginalFile extends FieldtypeFile { public static function getModuleInfo() { return [ 'title' => 'Original Image Field', 'version' => 1, 'summary' => 'An original image field that stores images outside the web root.', 'requires' => ['FieldtypeFile', 'InputfieldOriginalFile'], 'icon' => 'image', ]; } /** * Initialize the module and hook into Pages::saved to move files after the page is saved. */ public function init() { parent::init(); $this->addHookAfter('InputfieldFile::processInputFile', $this, 'moveFilesToCustomPath'); //$this->addHookBefore('Pages::saved', $this, 'moveFilesToCustomPath'); // werkt niet, doet niets // werkt niet // $this->set('destinationPath', '/home/portila/originalphotos/'); // Set the custom path for uploaded files // hook into delete page to remove the file from the custom path $this->addHookBefore('Pages::delete', $this, 'removeCustomFile'); // Hook into Pagefile::remove to ensure files are deleted from the custom path $this->addHookBefore('Pagefile::remove', $this, 'removeCustomFile'); } public function moveFilesToCustomPath(HookEvent $event) { $pagefile = $event->argumentsByName('pagefile'); if($pagefile->field->name != 'originalphoto') return; //if($pagefile->filename == '') return; // dit is NOOIT leeg! // dus checken als file bestaat if(!file_exists($pagefile->filename)) return; $customPath = '/home/portila/originalphotos/'; $newPath = $customPath . basename($pagefile->filename); // Move the file from the assets location to the custom path if (rename($pagefile->filename, $newPath)) { // Update the file's path in ProcessWire (not in the database) //$pagefile->filename = $newPath; // Log a message the new path $this->message("The file from the custom path: $newPath"); // log message with current page id $this->message("The page id is: " . $pagefile->page->id); } else { // Log an error if the file couldn't be moved $this->error("Could not move the file to the custom path: $pagefile->filename"); } } public function removeCustomFile(HookEvent $event) { $pagefile = $event->argumentsByName('pagefile'); if($pagefile->field->name != 'originalphoto') return; $customPath = '/home/portila/originalphotos/'; // error if $pagefile->filename is empty if($pagefile->filename == '') { $this->error("The file is empty"); return; } $newPath = $customPath . basename($pagefile->filename); // Check if the file exists if (!file_exists($newPath)) { $this->error("The file does not exist at the custom path: $newPath"); return; } // Remove the file from the custom path if (@unlink($newPath)) { // Log a message if the file was removed $this->message("The file was removed from the custom path: $newPath"); } else { // Log an error if the file couldn't be removed $this->error("Could not remove the file from the custom path: $newPath"); } } }
-
I suspected that the route I was crawling was not the correct one, so I ended up changing the course... with more succes ? field type <?php namespace ProcessWire; class FieldtypeTextZabun extends FieldtypeText implements ConfigurableModule { public static function getModuleInfo() { return array( 'title' => 'Zabun FieldtypeText', 'version' => 1, 'summary' => 'Zabun selector.', 'installs' => 'InputfieldTextZabun', 'icon' => 'home', ); } public function getInputfield(Page $page, Field $field) { $inputfield = $this->modules->get('InputfieldTextZabun'); /*$inputfield->set('zabundatabase', $this->get('zabundatabase')); $inputfield->set('zabunlocation', $this->get('zabunlocation')); $inputfield->set('zabunusername', $this->get('zabunusername')); $inputfield->set('zabunpass', $this->get('zabunpass'));*/ return $inputfield; } public static function getModuleConfigInputfields(array $data) { $inputfields = new InputfieldWrapper(); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'zabundatabase'); $f->label = __('Zabun database'); $f->icon = 'database'; $f->description = 'Zabun database'; $f->attr('value', isset($data['zabundatabase']) ? $data['zabundatabase'] : ''); $inputfields->add($f); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'zabunlocation'); $f->label = __('Zabun location'); $f->icon = 'server'; $f->description = 'Zabun location'; $f->attr('value', isset($data['zabunlocation']) ? $data['zabunlocation'] : ''); $inputfields->add($f); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'zabunusername'); $f->label = __('Zabun username'); $f->icon = 'user'; $f->description = 'Zabun username'; $f->attr('value', isset($data['zabunusername']) ? $data['zabunusername'] : ''); $inputfields->add($f); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'zabunpass'); $f->label = __('Zabun password'); $f->icon = 'key'; $f->description = 'Zabun password'; $f->attr('value', isset($data['zabunpass']) ? $data['zabunpass'] : ''); $inputfields->add($f); return $inputfields; } public function ___install() { // add dependencies copy( dirname(__FILE__).'/src/ZabunApi-master.php', $_SERVER['DOCUMENT_ROOT'].'/zabunapi.php' ); } public function ___uninstall() { // remove dependencies unlink( $_SERVER['DOCUMENT_ROOT'].'/zabunapi.php' ); } } input field: <?php namespace ProcessWire; class InputfieldTextZabun extends InputfieldText { public static function getModuleInfo() { return array( 'title' => 'Zabun InputfieldText', 'version' => 1, 'summary' => "Provides input for the Zabun Fieldtype", 'requires' => 'FieldtypeTextZabun', 'icon' => 'home', ); } public function __construct() { parent::__construct(); } public function renderReady(Inputfield $parent = null, $renderValueMode = false) { $url = 'https://unpkg.com/vue@3.2.22/dist/vue.global.prod.js'; $this->config->scripts->add($url); return parent::renderReady($parent, $renderValueMode); } public function ___render() { // $database = $this->zabundatabase; $out = '<div id="App">'; $out .= '<input '.$this->getAttributesString().' />'; $out .= '<div v-html="avar"></div>'; $out .= '</div>'; return $out; } } Thanks for reading my ramblings!
-
The custom fieldtype / inputfield can not add a record to the inputfield table... But if I add a record manually to the inputfield table, then I can edit the value with the module. As long as I don't empty the inputfield via the module and save, because then the record is deleted by the module. I don't know what I'm doing wrong. Can someone help me? FieldtypeZabun.module : <?php namespace ProcessWire; class FieldtypeZabun extends Fieldtype implements ConfigurableModule { public static function getModuleInfo() { return array( 'title' => 'Zabun Fieldtype', 'version' => 1, 'summary' => 'Zabun selector.', 'installs' => 'InputfieldZabun', 'icon' => 'home', ); } public function __construct() { parent::__construct(); } public function sanitizeValue(Page $page, Field $field, $value) { return $value; } public function ___wakeupValue(Page $page, Field $field, $value){ return $value; } public function ___sleepValue(Page $page, Field $field, $value) { return $value; } public function getInputfield(Page $page, Field $field) { $inputfield = $this->modules->get('InputfieldZabun'); $inputfield->set('zabundatabase', $this->get('zabundatabase')); $inputfield->set('zabunlocation', $this->get('zabunlocation')); $inputfield->set('zabunusername', $this->get('zabunusername')); $inputfield->set('zabunpass', $this->get('zabunpass')); return $inputfield; } public function getCompatibleFieldtypes(Field $field){ return null; } public function getDatabaseSchema(Field $field) { $schema = parent::getDatabaseSchema($field); $schema['data'] = "TEXT NOT NULL DEFAULT ''"; $schema['keys']['data'] = 'FULLTEXT KEY `data` (`data`)'; return $schema; } public static function getModuleConfigInputfields(array $data) { $inputfields = new InputfieldWrapper(); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'zabundatabase'); $f->label = __('Zabun database'); $f->icon = 'database'; $f->description = 'Zabun database'; $f->attr('value', isset($data['zabundatabase']) ? $data['zabundatabase'] : ''); $inputfields->add($f); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'zabunlocation'); $f->label = __('Zabun location'); $f->icon = 'server'; $f->description = 'Zabun location'; $f->attr('value', isset($data['zabunlocation']) ? $data['zabunlocation'] : ''); $inputfields->add($f); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'zabunusername'); $f->label = __('Zabun username'); $f->icon = 'user'; $f->description = 'Zabun username'; $f->attr('value', isset($data['zabunusername']) ? $data['zabunusername'] : ''); $inputfields->add($f); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'zabunpass'); $f->label = __('Zabun password'); $f->icon = 'key'; $f->description = 'Zabun password'; $f->attr('value', isset($data['zabunpass']) ? $data['zabunpass'] : ''); $inputfields->add($f); return $inputfields; } } InputfieldZabun.module : <?php namespace ProcessWire; class InputfieldZabun extends Inputfield { public static function getModuleInfo() { return array( 'title' => 'Zabun Inputfield', 'version' => 1, 'summary' => "Provides input for the Zabun Fieldtype", 'requires' => 'FieldtypeZabun', 'icon' => 'home', ); } public function __construct() { //require_once(dirname(__FILE__) . '/ZabunClass.php'); $this->zabundatabase = $this->get('zabundatabase'); $this->zabunlocation = $this->get('zabunlocation'); $this->zabunusername = $this->get('zabunusername'); $this->zabunpass = $this->get('zabunpass'); parent::__construct(); } public function renderReady(Inputfield $parent = null, $renderValueMode = false) { $url = 'https://unpkg.com/vue@3.2.22/dist/vue.global.prod.js'; $this->config->scripts->add($url); return parent::renderReady($parent, $renderValueMode); } public function ___render() { $this->setAttribute('type', 'text'); $this->setAttribute('id', 'zabunselector'); $this->setAttribute('name', 'zabunselector'); $out = ''; $out .= '<div id="App"><input '.$this->getAttributesString().' /></div>'; return $out; } public function ___processInput(WireInputData $input) { parent::___processInput($input); $this->value = $input['zabunselector']; return $this; } }
-
For a customer I needed a bunch of pictures to make a mosaic in Photoshop (cropped as a square) ? 20 lines of ProcessWire "et voila": a folder full of first pictures of every page from a certain template. <?php namespace ProcessWire; // boot api include('index.php'); // find estates from web database $estates = $pages->find("template=archief-pand"); // if estates count not zero if(count($estates)){ // loop over estates ($e is single estate) foreach($estates as $e){ // if images not null if(count($e->images)){ // get first image of estate gallery $firstPic = $e->images->first(); // resize and crop image to square 800x800px $firstPic = $firstPic->size(800,800); // if picture not null then copy picture to folder propics if(!empty($firstPic)) copy($_SERVER['DOCUMENT_ROOT'].$firstPic->url, $_SERVER['DOCUMENT_ROOT'].'/propics/'.$firstPic); } } }
-
Is there a reason why multiLine and newlineReplacement are not in the API doc? (but still work)
-
I have a problem with the redirects: I have one redirect: /site/be/en/ ->/projects/belgium/ But when I add another one like under, then I get error "The Redirect From URL already exists as a page path. Redirect not added. " /site/be/nl/ -> /nl/projects/belgium/ Why is this?
-
I don't know if this is known by you guys, but when I click on "I consent" in the notice panel and then go to manage with the js-pwcmb-notice-toggle, none of the checkboxes are checked. After a refresh at least one of the checkboxes is correctly checked in the manage panel. Curiously if not clicking on "I consent" in the notice panel, but going passing by preferences instead, then everything works as expected.
-
I have done a var_dump on the variable $LANG (user logged in or not logged in). When the user is NOT logged in, then the variable is a string: string(2) "FR" When the user is logged in, then the variable is an object: object(ProcessWire\LanguagesPageFieldValue)#331 (2) { ["default"]=> string(2) "FR" ["fr"]=> string(2) "FR" } Is this a bug or not? EDIT: $LANG is only an object on the home page and when logged in...
-
Is this a bug in Processwire or some PHP behavior? In _init.php there are two variables ($LANG and $sortNames): $LANG = $user->language->title; // in uppercase NL or FR $sortNames = array( 'NL' => array( 'apartment'=>'Appartement/Studio', 'house'=>'Huis/Villa', 'terrain'=>'Grond', 'parking'=>'Garage/Parkeerplaats', 'other'=>'Andere', 'commerce'=>'Commercieel' ), 'FR' => array( 'apartment'=>'Appartement/Studio', 'house'=>'Maison/Villa', 'terrain'=>'Terrain', 'parking'=>'Garage/Place', 'other'=>'Autre', 'commerce'=>'Commerce' ) ); If I use the variables in several templates, the the $LANG variable stays uppercase: echo $LANG; // gives the desired NL or FR foreach($sortNames[$LANG] as $k => $v){ echo $k.' '.$v.'<br>'; // gives the desired output from $sortNames } But if I do the same on the home template, then the $sortNames gives no output: echo $LANG; // gives the desired NL or FR foreach($sortNames[$LANG] as $k => $v){ echo $k.' '.$v.'<br>'; // stays empty !!! } The solution is simple but highly unusual, but in _init.php I done the following to correct the strange behavior: $LANG = strtoupper($user->language->title); Anyone has a clue why this is happening on home?
-
The issue has been fixed! FYI https://github.com/processwire/processwire-issues/issues/1031
-
I did not report my own post, but the one of someone with the same issue from 2016. My only goal is to get this resolved, but I don't use Github. All issues got resolved via the forum until now. I don't know why this issue is not.