saving ContentEditable HTML using PHP simple example

21 Dec 2019 | saving ContentEditable HTML using PHP simple example |

HTML supports (in most browsers) the contentEditable attribute which allows you to dynamically change a web page(s) content by simply editing the page, think of it like a WYSIWYG editor , but built-in to the browser. The purpose of this post is to show you how you can use this to create a simple, but powerful editing system using just PHP and a modern browser. All this code can be found in my GitHub Repository phpContentEdit

I’ll demonstrate how using just PHP , a modern browser (that supports ContentEditable) and a file system you can update your webpages  easily and quickly and with the proper security allow only registered users to make the changes. This example is most a proof of content, and is intended as a starting point for more sophisticated content editing capabilities.

General Steps for using PHP with ContentEditable

Basically, the script is broken up into two parts.

  • The plain HTML file we want to edit , which holds our content, we’ll call this content.html
  • The PHP script named index.php which reads and write the content.html and saves the changes

ContentEditable PHP work Flow

We first begin by just reading and displaying the content.html , and we also have a few {{placeholders}} inside content.html to replace things like title or JavaScript or action , basically anything dynamic, since remember the content.html is just a template file.  Here’s an example of what the top of the index.php looks like.

<?php

// Change the following to suit your environment
$basename= pathinfo(basename($_SERVER['SCRIPT_NAME']), PATHINFO_FILENAME);
$html_filename="content.html";   //html file that holds content, and is to be updated
$server_write_hmtl=$_SERVER['PHP_SELF'];  // PHP server page that writes the content
$secret_pw="admin"  ;  //secrete password to allow editable content
// End of configurable code 

error_reporting(E_ALL);
ini_set('display_errors', 'On'); //useful for debugging

ob_start(); //start buffering the content
session_start(); // start this session
date_default_timezone_set('America/New_York');  //Enable timezone

//Load in the corresponding HTML template file by the same name 
$page_html = file_get_contents($html_filename);  //load in our html content with proper placeholders

The content.html in this example uses  Bootstrap CSS to make it easier to style the page, but really any  valid HTML will work.  We also add a little allowEdit javascript within the content.html to basically put it into edit mode. This examples uses a very simplistic password prompt, but its recommended you secure the page more carefully for production systems. The prompt can be initiated by a button (as in this example) or via a secret queryString parameter, use your best judgement how to enabled editing

<input type="hidden" name="pw" value="" id="pw"><button type="submit" class="btn btn-primary" onclick="return allowEdit()"> Edit  </button>
 <script>
     function allowEdit()
     {
     var result= prompt('Credentials for editing. Make more secure. This is for demo purposes.');
     document.getElementById('pw').value=result;
     return result;
     }
   </script>

After the password prompt, we send the request back to the same index.php which checks that the user supplied password against our “secret” hash and if they match, reloads the content.html replacing the   <div class="editable" id="ce-1"> with   tags with    <div class="editable" contentEditabe="true" id="ce-1">  This then allows the user to make the edits inside the browser.

The we have a dynamically generated JavaScript Ajax function which attaches an event-handler to the onBlur event of the editable class attributes and grabs the id for that content and sends the changes back through the server.

<script>
    $('.editable').blur(function(){
      var myTxt = $(this).html();
      var myid = $(this).attr('id');
      
      console.log("Updating content: "+myTxt.trim() );
      console.log("content ATTR: "+myid);
  
      $.ajax({
          type: 'post',
          url:  '/PHP/phpContentEdit/index.php',
          data: 'content=' +myTxt+"&id="+myid+"&action=write"
      });
  });
  </script>

Finally , the index.php script gets the changes, checks its session to see that it’s authorized to write the changes to the disk, and then uses the

 new DOMDocument();  and   $xpath->query("//*[@id='".$id."']");  //search for our id   To walk the HTML DOM And update the proper id tags and replace the content on disk, here’s what the entire block of code looks like.

 //Ok lets re-write the content for this page
if ( isset($_REQUEST['action']) && $_REQUEST['action']=="write" && isset($_REQUEST['id']) )  // 
 {
      //REQUIRES THAT  DOMDocument is available  
      //https://www.php.net/manual/en/class.domdocument.php  
      //in order to properly parse HTML file and append to it.
      $doc = new DOMDocument();  //instantiate the HTML 
      $doc->loadHTML($page_html);  //load the HTML into the DomDocument Parser
      $id=$_REQUEST['id'];

      $replacement_html = htmlspecialchars(  trim($_REQUEST['content']) );
      echo "Editing content //*[@id='".$id."']";  //debug messages can be remove
      echo "\n Replacing with contnet \n";   //debug messages can be remove
      echo $replacement_html  ;

      //Now walk the matching Nodes and REPLACE with  the new fragment
      $xpath = new DOMXPath($doc);  //setup an Xpath Query object

      $nodes =  $xpath->query("//*[@id='".$id."']");  //search for our id
      foreach($nodes as $node) {
          $newnode = $doc->createDocumentFragment();

      if ( isset($replacement_html) )
        {     
            $newnode->appendXML($replacement_html);  //new content
        //    $node->appendChild($newnode);  //replace the existing content
            $node->parentNode->replaceChild($newnode, $node);
         
        }
      }
   
  //write the update page (Entire Page back to disk)
        if (is_writable($html_filename))
        {
         $bytes= $doc->saveHTMLFile($html_filename);
          echo "\n Success wrote $html_filename with $bytes bytes \n";
        }
        else
        die("File  $html_filename cannot not be written to check permissions");

        //return status and exit here.
        die("\n Success  AJAX Function write Content");
    }

Page Security considerations

As  I mentioned before , using this technique on a live site, with minimal security considerations is just inviting trouble, since, we’re allowing folks to edit our file system natively we are exposing our site to some potential damage. So to minimize that we may want to sanitize the edited HTML prior to writing it to disk, escaping any offending or malicious user input.

Best use cases for ContentEdit

ContentEdit can be used in its raw form as I outlined in this post, but it can also work with WYSIWYG editors so if you want to allow users to style the HMTL and be able to create more intricate page layouts and formatting, then be sure to use one of the many HTML WYSIWYG editors and then just save its changes.

Demo Page

Go to my Github and download the example and throw it up on your PHP server to see it in action.

2 thoughts on “saving ContentEditable HTML using PHP simple example

  1. Reply Nelson K Dec 22,2019 10:19 am

    Can I use this on any web page , or does the conteditsble need to be a specific format?

    • Reply Tony B. Jan 1,2020 6:36 pm

      Nelson, it should work on any web page, the only requirements are that the HTML page is writable (by the web server ) and that its wrapped inside teh

      my editable contnetn here

Leave a Reply