Jump to content

ren

Members
  • Posts

    24
  • Joined

  • Last visited

Everything posted by ren

  1. Opened an issue https://github.com/processwire/processwire-issues/issues/813
  2. Upgraded a site from 3.0.98 to 3.0.123 and now all admin pages are timing out. The problem seems to be debug mode in combination with using WireCache for around 3,400 items. Confirmed on a fresh install, but would appreciate if anyone could try replicating before I file an issue... To replicate, in config.php: $config->debug = true; $config->debugTools = array( 'pages', 'api', 'session', 'modules', 'hooks', 'database', 'db', 'timers', 'user', 'input', 'cache', ); Fill the cache with some dummy data: for ($i = 1; $i < 4000; $i++) { $cache->save($i, $i); } Then try and view any admin page. The issue goes away if 'cache' is removed from $config->debugTools , or if the site is downgraded to 3.0.98. Happens with or without Tracy.
  3. The header and footer are looking lovely with the original logo. Just noticed that the home page section title "ProcessWire News & Community" is replaced once the content is pulled in (LInux Firefox & Chrome).
  4. LInux Chrome (Firefox is the same) (Arial)
  5. There is already some information on how to do this but it's a bit scattered, so here's a quick tutorial... This is how $session->CSRF->hasValidToken() handles AJAX requests, by getting the token name and value from request headers: if($this->config->ajax && isset($_SERVER["HTTP_X_$tokenName"]) && $_SERVER["HTTP_X_$tokenName"] === $tokenValue) { $valid = true; } else if($this->input->post($tokenName) === $tokenValue) { $valid = true; } So all we need to do is to pass the name and value to our JavaScript and set the right headers with our AJAX request. We could instead of setting headers put the name and value pair into the body of a POST request, as the second conditional doesn't care if the POST request is received via AJAX or not. But this limits the request to POST and the body data type to either multipart/form-data or application/x-www-form-urlencoded (because that's all that PHP's $_POST superglobal will handle). Admittedly this might be 99% of use cases, but for example if a GET request invokes significant processing then CSRF protection could be used to prevent a DOS attack on the endpoint. So, for the sake of a bit more flexibility, and to be more in keeping with what PW expects, we'll use request headers. I find it neater to write the token name and value into HTML and retrieve that using JavaScript DOM functions, instead of writing JavaScript with PHP ๐Ÿ˜. So somewhere, maybe in init.inc.php, get the token name and value: $csrfTokenName = $session->CSRF->getTokenName(); $csrfTokenValue = $session->CSRF->getTokenValue(); Then in a global footer template: <div class="js-csrf-token" style="display:none;" data-csrf-token-name="<?php echo $csrfTokenName; ?>" data-csrf-token-value="<?php echo $csrfTokenValue; ?>"></div> Now to retrieve the token in JavaScript: function getCsrfToken() { const csrfTokenNode = document.getElementsByClassName('js-csrf-token')[0]; return { name: csrfTokenNode.getAttribute('data-csrf-token-name'), value: csrfTokenNode.getAttribute('data-csrf-token-value'), } } Then in any AJAX request: const csrfToken = getCsrfToken(); let xhr = new XMLHttpRequest(); // ... // open the request and do some configuration // ... xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // tell the server and PW that it's an AJAX request xhr.setRequestHeader('X-' + csrfToken.name, csrfToken.value); // create a header with the token // ... // send the request // ... And that's all, in the endpoint just do... if ($session->CSRF->hasValidToken()) { // works for AJAX! } This has used the default CSRF token created for every session, but to create and use a different token just specify an id: $csrfTokenName = $session->CSRF->getTokenName('myAjaxToken'); // this creates a token if one with the given id doesn't exist $csrfTokenValue = $session->CSRF->getTokenValue('myAjaxToken'); and... if ($session->CSRF->hasValidToken('myAjaxToken') { // ... }
  6. Ooh, that sounds cool! ๐Ÿ‘ Yeah, that makes sense. Forgot about that lovely new addition! Looking forward to not writing my own functions ๐Ÿ˜€ Agreed that there's no harm in guarding against any potential changes. AH! ๐Ÿ’กRight, so in the example code, $form->processInput applies the Inputfield sanitizers but $pages->add does not? Thanks for the wide-ranging examples!
  7. If I were explaining why I love PW to another developer I'd say... Unopinionated Powerful stable API Security Extremely active, friendly, *knowledgeable* community. I feel like that covers the major pain points that CMS/CMF developers feel, particularly 1) and 2). PW has so many great points that it's tempting to want to cover them all. I kinda agree with others that maybe there are too many points, and too much content.
  8. Seconded. I find the body text on blue background slightly hard to read.
  9. The search box doesn't close when losing focus, and tab doesn't shift focus to the other menu items. (Linux Chrome 68.0.3440.75)
  10. Love it! The only thing I'm not sure about is the emphasis on... I feel that a low maintenance overhead is already strongly implied by reliability and security sections. I like to run updates if only to keep the CK Editor plugin up-to-date, which *does* have semi-regular security patches. It might not appeal to developers for whom updates are bread and butter. I'd rather see something like... Lower maintenance costs, because security, reliability, and a stable API resulting in painless upgrades. Yeah, I once did a major version PW upgrade on a fairly complex 30,000+ page site and *nothing* broke! Zero. Zilch. Nada. It brought tears to my eyes. A lack of breakage that is unheard of in CMS land. Compare with regular minor version breakage for some other CMS ๐Ÿ˜€
  11. Hi, This is kind of an open ended question, but I find I'm not using $santizer much because the PW API takes care of most sanitization, and I'm wondering if this is actually ok. Take for example a contact form which creates a page for each message and emails admin. Something like this... Edit: this is incorrect // The page's Inputfields run the same sanitizers as processInput() above // Optionally with stripTags enabled See the reply from @teppo $form = $modules->get('InputfieldForm'); $form->action = $page->url; $fullNameField = $modules->get('InputfieldText'); $fullNameField->name = 'fullName'; $fullNameField->required = 1; $emailField = $modules->get('InputfieldEmail'); $emailField->name = 'email'; $emailField->required = 1; $messageField = $modules->get('InputfieldTextarea'); $messageField->name = 'message'; $messageField->required = 1; $form->append($nameField); $form->append($emailField); $form->append($messageField); $csrfTokenName = $session->CSRF->getTokenName(); $csrfTokenValue = $session->CSRF->getTokenValue(); $fullNameMarkup = ''; $emailMarkup = ''; $messageMarkup = ''; if ($input->post->submit) { // processInput assigns $input values to the form Inputfields by calling each Inputfields' setAttribute() method // setAttribute() calls setAttributeValue() which does sanitization, e.g. // InputfieldText runs $sanitizer->text with stripTags set to false by default // InputfieldTextarea runs $sanitizer->textarea with stripTags set to false by default // InputfieldEmail runs $sanitizer->email $form->processInput($input->post); // Output needs to be entity encoded $fullNameMarkup = $sanitizer->entities($form->fullName->value); $emailMarkup = $sanitizer->entities($form->email->value); $messageMarkup = $sanitizer->entities(nl2br($form->message->value)); if (!$form->getErrors()) { $adminEmail = sendEmailToAdmin($fullNameMarkup, $emailMarkup, $messageMarkup); if (!$adminEmail) { return wireRenderFile($config->paths->templates . 'includes/contact/failure.inc.php', [ 'type' => 'send email' ]); } try { $createPage = $pages->add('contact', '/contacts/', [ // The page's Inputfields run the same sanitizers as processInput() above // Optionally with stripTags enabled 'contact_full_name' => $form->fullName->value, 'contact_email' => $form->email->value, 'contact_message' => $form->message->value, ]); } catch (WireException $e) { return wireRenderFile($config->paths->templates . 'includes/contact/failure.inc.php', [ 'type' => 'create page', 'error' => $e ]); } return wireRenderFile($config->paths->templates . 'includes/contact/success.inc.php' } } return wireRenderFile($config->paths->templates . 'includes/contact/form.inc.php', [ 'fullNameMarkup' => $fullNameMarkup, 'emailMarkup' => $emailMarkup, 'messageMarkup' => $messageMarkup, 'csrfTokenName' => $csrfTokenName, 'csrfTokenValue' => $csrfTokenValue, 'errors' => $form->getErrors(), ]); So processInput() ensures the email address is valid, and all markup is entity encoded. Even stripping tags seems unnecessary since page fields always give entity encoded output unless output formatting is disabled. So I only really use $sanitizer->entities(), $sanitizer->selectorValue(), and occasionally $sanitizer->name(); Am I missing something? How do you use $sanitizer?
  12. Patch #5463406 solves both issues ๐Ÿ‘๐Ÿ˜€ Thanks Ryan
  13. Thanks matjazp, I've added to the issue report.
  14. Will do. With no other confirmed replications yet, I'm wondering if it's a server config issue, although I've no idea what that may be. Thanks Edit: just seen Soma has replicated.
  15. It's replicated on two servers, one running PHP 5 and the other PHP 7. It's also replicated in Chrome on a Windows machine, so it doesn't seem to be a Linux browser issue. The only other thing to try is a different internet connection. Thanks
  16. Hi folks, wondering if anyone's encountered this problem before?... 1) Trash a page from the page tree (screenshot1.png) 2) The page is removed from the page list (screenshot2.png) 3) Close the page tree (screenshot3.png) 4) Open the page tree, the page reappears (screenshot4.png) If I do a browser refresh the page permanently disappears, so it seems the problem is with the AJAX admin. Replicated with: Clean installations of ProcessWire v 3.0.98, 3.0.96 and 3.0.34 With and without AdminKitUI No additional modules Basic profile Linux Chrome 67.0.3396.99 Linux Firefox 61.0.1 PHP 5 PHP 7 Restrictive and fully permissive file permissions Sometimes it takes adding and deleting a few pages for the problem to appear. There are no console errors. Thanks
  17. ren

    Support contract

    Clarification: by 'setup costs' I mean any initial costs associated with getting to grips with things, i.e. the codebase, server and deployment strategy etc.
  18. ren

    Support contract

    Hi Victor, Just PM'd you. Thanks
  19. ren

    Support contract

    Hi folks, My department is planning to move up to five of our employer's websites in-house and onto ProcessWire from a CMS which has not seen much development in the last few years. They're B2B magazine websites and we feel that ProcessWire would be a great fit. But there are concerns over support. I'm the only server side programmer, so what would happen were I to leave or be hit by the proverbial bus? So we're looking for some kind of insurance. Thinking along the lines of a support contract, covering maybe 2 hours of support time per month. With a commitment to become more involved should the need arise, so providing more support if needed to someone who takes over my role, or in the 'bus' type emergency, be willing to take over full support duties for a limited period of time. The 2 or so hours would be used for providing advice if I were to really get stuck. But I'm happy using the forums for help, and I've built a prototype of one of the sites without huge difficulty (go ProcessWire!), so under normal circumstances they probably won't be used. The five sites are all quite large (the prototype site has 40 templates and 95 fields), consisting of news sections, a jobs section, a business directory, reader polls and social media integration. Some of the sites allow membership for the business directory, so companies can login and manage their listing and upload press releases, via a custom dashboard (implemented as a Process module). All code will be commented and held in a git repo. We're located in the UK. Email support would be sufficient I think. If you're interested, please PM me with a rough estimate of costs for: The ~ 2 hours per month standard support. Full 'emergency' support of all 5 websites. Any one-off setup costs. And/or suggest an alternative pricing structure / proposal. Again at this stage we're just looking for a rough idea of costs and who would be available, so ballpark figures would be fine If you could also provide a link to your website please. Please let me know if you would like any further information. Thanks
  20. Doh. Yes, that works Prefer this to matching urlSegment I think. Thanks!
  21. Hi @Robin S, Thanks, Tracy Debugger is looovely. I did as you said, and put db calls to log both cases (redirect and no redirect): // do not redirect if page matches: if($this->page->template != "admin" // any non-admin page || $this->page->is($this->redirectPage) // the dashboard page (prevent infinite loop) || $this->page->parent->is('/admin/login/') // various attempts to allow logging out || $this->wire("process") == 'ProcessLogin' || strpos($this->page->url, $this->wire('config')->urls->admin . 'login/logout') !== false ) { bd($this->page, 'no redirect page'); return; } bd($this->page, 'redirect page'); When I tried to logout it logged both cases, with 'redirect page' first: data protected => array (3) title => "Login" (5) process => "ProcessLogin" (12) urlSegment => "logout" (6) ... for some reason 'ProcessLogin' is sailing through the conditional. Followed by 'no redirect page': data protected => array (2) title => "Dashboard" (9) process => "ProcessDashboard" (16) The first log gave me the idea to match the urlSegment, which works a charm! So if it's of any use to anyone, the working code is: if($this->page->template != "admin" || $this->page->is($this->redirectPage) || $this->input->urlSegment1 == 'logout') { return; } // find roles set in module configuration and create array $roles = explode(',', $this->userRoles); // for each user in module config check to see if current user foreach ($roles as $key => $val) { // get a role from the roles array $roles[$key] = trim($roles[$key]); // if current user found with role then redirect if($this->user->hasRole($roles[$key])){ // redirect session to page stored in config $this->session->redirect($this->redirectPage); // code should never get here but this is a simple fallback break; } } Thanks Robin, you've been a great help, and I'm sure to be using Tracy Debugger again
  22. Hi all, I'm creating a website for a magazine publisher. This will include a supplier section with press releases attached to company profiles. The idea is that companies can register and manage their profile and press releases (CRUD) via a dashboard. The dashboard is a Process module. Ben Byford's RedirectAdminPages module is being used to lock out the rest of the backend, with a few modifications. The following code should redirect every admin page to the dashboard page but still allowing logging out. However logging out just redirects to the dashboard page: // do not redirect if page matches: if($this->page->template != "admin" // any non-admin page || $this->page->is($this->redirectPage) // the dashboard page (prevent infinite loop) || $this->page->parent->is('/admin/login/') // various attempts to allow logging out || $this->wire("process") == 'ProcessLogin' || strpos($this->page->url, $this->wire('config')->urls->admin . 'login/logout') !== false ) { return; } // find roles set in module configuration and create array $roles = explode(',', $this->userRoles); // for each user in module config check to see if current user foreach ($roles as $key => $val) { // get a role from the roles array $roles[$key] = trim($roles[$key]); // if current user found with role then redirect if($this->user->hasRole($roles[$key])){ // redirect session to page stored in config $this->session->redirect($this->redirectPage); // code should never get here but this is a simple fallback break; } } } } I'm surprised that this URL matching doesn't work: || strpos($this->page->url, $this->wire('config')->urls->admin . 'login/logout') !== false Because this does work for allowing page edit: || strpos($this->page->url, $this->wire('config')->urls->admin . 'page/edit') !== false Any ideas? That issue aside, as a learning process I'm going to re-implement the dashboard as front-end pages. I guess that the advantage of using the ProcessWire back-end is most of the functionality is already there, you don't need to create forms and handle the processing, create / import css etc. So it'll be interesting to see how much of a difference this makes, and how much control each approach provides. I'd love to have some thoughts and feedback from those of you who've tried both methods? PS this will be my third website created with ProcessWire and it's already been a lot of fun, and as a CMS it 'just feels right', so a big thanks to Ryan and everyone who has contributed. Thanks
ร—
ร—
  • Create New...