robinc

Non db dependent 'offline' page - for when pw cant reach the db

9 posts in this topic

With any website, there is the possibility of db issues - overloaded server, network connectivity if the db is on another machine in the hosting network, etc.

I would love to see a feature where if there is any reason the db fails or cannot be accessed, then pw displays a dedicated page that is stored in the filesystem - instead of displaying nothing, or an ugly mysql error. Obviously it would be good to log the error, and possibly send a notification to the admin (email?).

This gives us the opportunity to still present a professional front (albeit with no functionality) while problems are resolved behind the scenes. I cannot think of a company I have worked for that hasn't had db errors at times

What are your thoughts?

2 people like this

Share this post


Link to post
Share on other sites
34 minutes ago, robinc said:

Obviously it would be good to log the error, and possibly send a notification to the admin (email?).

Database errors are always logged. You will find entry in your /site/assets/logs/errors.txt file

2017-03-18 16:05:27    ?    http://example.org/?/    Error:     Exception: SQLSTATE[HY000] [1049] Unknown database 'example' (in .../wire/core/ProcessWire.php line 375)

Depending on your config.php settings an Email will be sent

/**
 * Admin email address
 *
 * Optional email address to send fatal error notifications to.
 *
 * #input email
 * @var string
 *
 */
$config->adminEmail = '';

In case of fatal errors the following html file will be send

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
    <title>500 Internal Server Error</title>
</head>
<body>
    <h1>Internal Server Error</h1>
    <p>The server encountered an internal error or misconfiguration and was unable to complete your request.</p>
    <p>{message}</p>
</body>
</html>

You can modify it. You'll find the file (default installation) in /site/templates/errors/500.html

10 people like this

Share this post


Link to post
Share on other sites

Thank you :)

There is so much available in PW that sometimes one forgets it's there.

4 people like this

Share this post


Link to post
Share on other sites

It would be nice to have an admin interface for managing this file (and linked css). Potentially with wysiwyg editing and preview function, any maybe an 'export from page' option, to create the static file.

 

Share this post


Link to post
Share on other sites

You can create a page with a ckeditor field and then hook on save to rewrite the static file. No time to give you code now.

Share this post


Link to post
Share on other sites

And here goes some code. Place this on site/ready.php (or create a module from it) and edit the first lines to your liking:

 

/*************************/
/******* EDIT HERE *******/
/*************************/

// ID of the page where the custom content is
$this->pageID = 1;

// name of the field where the custom content is
$this->fieldName = 'body';

// name of html tag and id from the parent of the custom content on the 505 file
$this->elementTag = 'div';
$this->elementID = 'message';

/*************************/
/******* END EDIT ********/
/*************************/


// regex to get the contents of parent element
$this->regex = '/(<'.$this->elementTag.'\sid=("|\')?'.$this->elementID.'("|\')?>)([^<]|<.+>.*<\/.+>)+(<\/'.$this->elementTag.'>)/i';

// On save the content of the field on the 505.html file
$this->addHookAfter('Pages::saved', function(HookEvent $event) {
  
    $page = $event->arguments[0];

    if($page->id !== $this->pageID) return;

    $file = wire('config')->paths->templates . '/errors/500.html';

    $content = file_get_contents($file);
    $field = $this->fieldName;

    $content = preg_replace($this->regex, '$1'.$page->$field.'$3', $content);

    file_put_contents($file, $content);

});

// On render the edit page, save the content of 505.html file on the field to show it
$this->addHookBefore("ProcessPageEdit::buildFormContent", function(HookEvent $event) {
  
    $page = $event->object->getPage();

    if($page->id !== $this->pageID) return;

    $file = wire('config')->paths->templates . '/errors/500.html';

    $content = file_get_contents($file);

    preg_match($this->regex, $content, $matches);

    if($matches) {

        $page->of(false);
        $field = $this->fieldName;
        $page->$field = $matches[0];
        $page->save($this->fieldName);

    }

});

 

The above code assumes that your "505.html" file has a <div> with the id "message" in it, you just have to adapt it to yours.

2 people like this

Share this post


Link to post
Share on other sites

one thing that is not working for me with the offline files in the template folder:

it seems that if you use delayed output, then there is something in the output buffer already that gets prepended to the html file when rendered;

not sure how to fix this, but it's kind of a problem, can't render a clean 500 error page because of this, due to a bunch of markup being output above the opening <html of the error file...

Share this post


Link to post
Share on other sites
On 3/28/2017 at 2:48 AM, diogo said:

And here goes some code. Place this on site/ready.php (or create a module from it) and edit the first lines to your liking:

 


/*************************/
/******* EDIT HERE *******/
/*************************/

// ID of the page where the custom content is
$this->pageID = 1;

// name of the field where the custom content is
$this->fieldName = 'body';

// name of html tag and id from the parent of the custom content on the 505 file
$this->elementTag = 'div';
$this->elementID = 'message';

/*************************/
/******* END EDIT ********/
/*************************/


// regex to get the contents of parent element
$this->regex = '/(<'.$this->elementTag.'\sid=("|\')?'.$this->elementID.'("|\')?>)([^<]|<.+>.*<\/.+>)+(<\/'.$this->elementTag.'>)/i';

// On save the content of the field on the 505.html file
$this->addHookAfter('Pages::saved', function(HookEvent $event) {
  
    $page = $event->arguments[0];

    if($page->id !== $this->pageID) return;

    $file = wire('config')->paths->templates . '/errors/500.html';

    $content = file_get_contents($file);
    $field = $this->fieldName;

    $content = preg_replace($this->regex, '$1'.$page->$field.'$3', $content);

    file_put_contents($file, $content);

});

// On render the edit page, save the content of 505.html file on the field to show it
$this->addHookBefore("ProcessPageEdit::buildFormContent", function(HookEvent $event) {
  
    $page = $event->object->getPage();

    if($page->id !== $this->pageID) return;

    $file = wire('config')->paths->templates . '/errors/500.html';

    $content = file_get_contents($file);

    preg_match($this->regex, $content, $matches);

    if($matches) {

        $page->of(false);
        $field = $this->fieldName;
        $page->$field = $matches[0];
        $page->save($this->fieldName);

    }

});

 

The above code assumes that your "505.html" file has a <div> with the id "message" in it, you just have to adapt it to yours.

Thanks @diogo  for this.

___________________________________
Get Assignment help.

Edited by adrian
Removed spammy link
1 person likes this

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 Brian Scramlin
      Hey!
      Quick question, 
      Should I limit how many find() methods I use on a single page? Is it fairly resource-intensive?
      I am getting consistent 
      2006 MySQL server has gone away errors and have followed all the suggestions I can find, but wonder if I am just "overloading" my server resources with database requests or something like that?
      Thank you!
    • By kixe
      Today I have been running in mysql errors using @renobird s Module MarkupActivityLog which still uses mysqli Driver.
      @all developers
      Although mysqli is still supported PDO driver is the default database driver in PW since https://processwire.com/about/news/introducing-processwire-2.4/
      and its strongly recommend to all module authors to use/change-to PDO driver instead of mysqli.

      @renobird I have sent a pull request.
      A list of other affected modules not updated until now.
      (I try to keep them up to date. Please help)
      @apeisa ProcessTrashman, ProcessRedirects
      @netcarver ProcessDiagnostics
       
    • By suntrop
      Hi all
      I have big troubles with my DB backups and phpMyAdmin. I can't manage to import a backup.
      The phpMyAdmin export settings are left to the defaults. The error message I get:
      #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INSERT INTO `caches` (`name`, `data`, `expires`) VALUES ('ModulesUninstalled.in' at line 11 When I delete the complete 'cache' section there are almost for all tables the same errors. (part of the dump attached)
      I had this problem before and back then (couple months ago) I think I copied almost every table individually. I thought it was specific to that DB. But I can't do a dump/import of any of my PW installations.
      MySQL: 5.6.27
      PHP version: 7.0.11
      phpMyAdmin: 4.5.5.1
      Anybody knows that problem? Or what to do?
      phpMyAdmin SQL Dump.sql
    • By mrjasongorman
      I'm just wondering exactly what MySQL permissions are required for ProcessWire? From a security point of view i would prefer to lock down the MySQL user that ProcessWire uses to the least amount of privileges needed.
      I guess it's SELECT, INSERT, UPDATE, DELETE, but do any modules create additional indexes?
      Any help on this would be great.
    • By Harmen
      Hey all,
      For my website I had to make a connection with an external DB. In that DB there are categories of products in different languages, and I want to import these categories in the languages that are available in processwire, I can do that with a very long code but I want to make it shorter. So I wrote a function to get the categories, but the different languages of the category names not, only if I insert the ISO-code hard-code. So here is my code:
      protected function get_category() { $languages = wire("languages"); try { $prestashp = $this->get_dbPrestashop(); foreach($languages as $language) { $iso_code= $language->name ; $categories = $prestashp->query( "SELECT l.id_lang, l.iso_code, cl.description, cl.name AS category_title, cl.id_shop, c.active, c.id_category, c.id_parent, c.position, cl.link_rewrite FROM ps_category c INNER JOIN ps_category_lang cl ON c.id_category=cl.id_category LEFT JOIN ps_lang l ON cl.id_lang=l.id_lang WHERE c.active='1' AND cl.id_shop='1' AND c.id_parent = '2' ORDER BY c.position "); } }catch(Exception $e) { $this->message('Failed to show categories. Try again later.'); return false; } return $categories; }  
      So in the DB there is Deutsch, Dutch, English(default), Spanish, Italian. And when I edit the template the different languages of the category names need to be imported in the right tab of the field. 
      https://gyazo.com/52a3549a8adaed2d5f44cac6dfb6d9d3 As you can see, there are language tabs above the field, and the names of the category in that language need to be insterted there. 
      Anyone have an idea how I can fix this?