Cruddiy: a no-code Bootstrap CRUD generator

November 2020: Cruddiy now supports creating and deleting table relations (based on foreign keys) for cascading deletes/updates and and prepopulating select lists. Read more here.

So you have a MySQL database and a user who should be able to do some standard database actions, like Create, Read, Update or Delete database records. Nothing fancy.
And, this is a non-technical user, so you don’t want to give them access to phpMyAdmin, which is too difficult. Or let alone give them command line access. So you need some simple database forms, built on top of your MySQL database, but you also don’t want to handcode the same PHP CRUD pages again!

Now you can use Cruddiy (CRUD Do It Yourself) and quickly generate clean CRUD pages with zero coding.

You’ve probably seen pages like this a thousand times before. And if you have a MySQL database you can now make them yourself with just a few clicks.

Pages like these are generated without writing a single line of code. With proper titles, pagination, actions (view/edit/delete) and sorting included.

Above is the old Bootstrap 3 look. This is the new Bootstrap 4 look:

20200409-cruddiy-app-index.png (1157×729)
Cruddiy with Bootstrap 4 and search

I got tired of programming the same pages over and over again for some simple database forms. So in classic yakshaving fashion I decided to automate this, and built a generator that generates PHP CRUD pages.

Cruddiy is a no-code PHP generator that will generate PHP Bootstrap CRUD pages for your MySQL tables.

The output of Cruddiy is an /app folder which includes everything you need. You can rename and move this folder anywhere you want and even delete Cruddiy when you’re done (or run it a couple of times more to get your app just the way you like it). Cruddiy is only used to generate the /app folder. And the /app folder is what your user will use.

Why Cruddiy, tool xyz does the same thing!

Most MVC frameworks (e.g. Symfony, Django or Yii2) are of course also able to generate CRUD pages for you. I have used all of these. But usually you end up with at least 80 Megabytes of code (no joke) and with all kinds of dependencies that you need to deploy and maintain for just a couple of PHP pages! This rubs me the wrong way.
And of course there are many other PHP Crud generators around, but they are not libre or, more often than not, built on top other larger frameworks: so they have the same problem. Or they simply lack something else. So when I couldn’t find anyone that fit my needs I decided to make Cruddiy.

Cruddiy goals and characteristics

  • Simple
    • No dependencies, just pure PHP.
    • Written in PHP and output in PHP. When the generator runs correctly, your generated app will run correctly.
  • Clean
    • Just generate what’s needed, nothing else.
  • Small
    • If it wasn’t obvious from the above, the app it generates should be small. Kilobytes not megabytes.
  • Portable
    • Cruddiy generates everything in one single /app folder. You can move this folder anywhere. You don’t need Cruddiy after generating what you need.
  • Bootstrap
    • Bootstrap looks clean and is relatively simple and small. I use Bootstrap 3 because I like and know it a bit better than 4.

FAQ

Why PHP?

  • Love it or hate it: but PHP is ubiquitous. You can download Cruddiy on most webservers and you’re good to go. wget the zip -> unpack -> check webserver permissions (chmod) -> surf to the unpacked folder in your browser and follow instructions.
  • Cruddiy is of course a sort of templating engine. It stamps out code based on templates. And if PHP is anything, it is in fact by default a template engine itself. So it’s a pretty good language for this kind of thing.
  • Cruddiy only works with MySQL (for now): and MySQL and PHP are of course two peas in a pod.

Cruddiy does not follow the MVC paradigm!

Yes, looks elsewhere if you need this. This is not a framework.

Your code is full of dirty hacks

Sure, the generator does quite a bit of array mangling and dirty string replacement, but the PHP pages Cruddiy generates are as clean as they come. And when you’re done generating pages, you can just delete Cruddiy. It completely builds a self-contained portable app that will run on almost any webserver with PHP (i.e. most).

Your generated code is incomplete

At the moment what’s lacking is error value checking on database inserts/updates (all fields are required and it doesn’t check field types: integers vs dates etc.). These will throw general errors or don’t do anything at all. I will probably improve this, but for most use-cases (see above) this should not be a problem. The generated code does use prepared statements and should not be vulnerable to SQLi. But hey, please drop me a line if you find something!

Next features?

I might add these things:

  • Darkmode
  • Bootstrap 4 theme ✔️ Fixed per 20200803
  • Export to CSV or XLS (users probably want this more often than not)
  • Rearrange column order
  • Search records (at the top of the page) ✔️ Fixed per 20200722
  • User registration (simple table with username and password: .htaccess works for now)
  • Define table relations (use for cascading deletes etc.) ✔️ Fixed per 20201126
  • More specific field types (ENUM = drop-down list BOOLEAN = checkbox etc.)
  • More and better input validation
  • Catch more database errors
Cruddiy in action.

Also published on Medium.

23 thoughts on “Cruddiy: a no-code Bootstrap CRUD generator”

  1. hello, I’m still new to web programming. I have not mastered the use of php framework correctly. Every time I want to make a CRUD application I have to code every function needed. this also happens when updating / adding columns to the table. CRUDDY is very simple and helpful. this makes me excited again. thank you

  2. this is exactly what I have been wanting for YEARS! thank you. I am planning on modifying it a bit so I can use it as an include inside my existing bootstrap template

  3. Wow. Really thanks for this. Just like Mike, I have been wanting this for years. I had also started working on something similar on my own, but never got to it. I will make some minor mods to it, to use it inside my application, but it mainly cosmetics, nothing more. Thank you so much

  4. I really hope you keep working on this code because the competition is utterly garbage. All of them are bloated and requires additional libraries and frameworks to install. Some of us are still on shared hosting and using Composer or an entire web framework quickly turns into bloat and maintenance nightmare.

    I just spent the entire day trying out different CRUD solutions for PHP/MYSQL and yours was by FAR the easiest to install and use, like orders or magnitude easier. I love that you decide to not use composer or a web framework for your code; for once uploading a zip file and unzipping it actually installs an app.

    Unfortunately, I need to be able to specify relational logic and what not, so I can’t use your code. But please keep working on it! It’s really the best solution for simple CRUDs.

  5. Just WOW…..
    I’m an architecture student and I have a small project idea that involves creating different databases and I know how to do a simple CRUD, it takes me so much time…
    It works but is just too messy, every time I need to change something I have to almost start from 0.
    Cruddiy is just awesome, it works really well, it is easy to use and it looks soooo well.

    Thank you very much for the effort you put into this project!

    1. I have been checking the code and it is a masterpiece!
      I did some changes that maybe someone finds interesting:
      1st – I use some Boolean values and what I did is add another case in the update function that checks if the column is tinyint(1) then creates a dropdown with values 0 and 1. I think maybe this can help avoid inserting an invalid value.

      2nd – I added a small text next to the “# results” text that shows the Order and Sort so in case you are doing some stuff and come back to that tab you know how it was ordered.

      3rd – I made that the Update page returns the updated ID to the main page then there I check each row and if a row ID matches the updated ID I use the table-success class for that row. Using this you immediately see the updated record. I tested this for one page of results only, maybe the page number could be passed like Main page > Update page > Main page so it redirects you to the page where you updated the value.

      4th – I added a table-hover just in case the page has too many records.

      5th – I added a number type field in the index page of the set up where you can select the number of elements per page then this gets saved in the config file then I deleted the variable from the table-index page. So it is easier to modify the variable if it is in the small config file.

      6th – I added another case in the generator that searches for int (so it gets tinyint, int, smallint, bigint…) and then the field it created is a number one so it prevents you from entering a wrong value and it shows in red border and prevents you from submitting.

      7th – I am doing one modification that adds a small caption below the inputs in the update page that lets you know the allowed information and the max values so it is easier to identify.

      Well that is it for now, I really love your creation is just beautiful.
      Thank you very much.

        1. Hello, sorry to write the changes here, I still don’t know how to use GIT the correct way 🙁 I looked at the About page but the email link was broken.
          I am not sure if this will be correctly formated, if you see that it looks weird and you want you can send me an email and I will send you through email.

          1st – For the Boolean values and number fields (int, bigint…) I added this to the generate.php

          case (preg_match(“/tinyint\(1\)/i”, $columnname) ? true : false) :
          return 4;
          break;
          case (preg_match(“/int/i”, $columnname) ? true : false) :
          return 5;
          break;

          Next when creating the update fields I add this:

          case 4:
          $regex = “/'(.*?)’/”;
          preg_match_all( $regex , $columns[‘columntype’] , $enum_array );

          $create_html [] = ‘
          ‘.$columndisplay.’
          ‘;

          $create_html [] .= ‘ 0’;
          $create_html [] .= ‘ 1’;

          $create_html [] .= ‘

          ‘;
          break;

          case 5:
          $create_html [] = ‘
          ‘.$columndisplay.’
          <input type="number" name="'. $columnname .'" class="form-control" value="”>

          ‘;
          break;

          2nd – In the document templates.php after

          echo ” ” . $number_of_results . ” results”;

          I added:
          if(isset($_GET[‘order’]) && $_GET[‘order’]!=”){
          if(isset($_GET[‘sort’]) && $_GET[‘sort’]!=”){
          echo ” – Order by ” . $_GET[‘order’] . “” . $_GET[‘sort’] . ‘‘;}}

          3rd – In the template.php I changed this:

          if(!$stmt->execute([ {UPDATE_SQL_COLUMNS} ])) {
          echo “Something went wrong. Please try again later.”;
          header(“location: error.php”);
          } else{
          $stmt = null;
          header(“location: {TABLE_NAME}-index.php”);
          }

          into this:

          if(!$stmt->execute([ {UPDATE_SQL_COLUMNS} ])) {
          echo “Something went wrong. Please try again later.”;
          header(“location: error.php”);
          } else{
          $stmt = null;
          header(“location: {TABLE_NAME}-index.php?lastUpdated=$ID”);
          }

          Then in the template.php where the table is generated I added this so the row will be in green, the issue I thought about but I still haven’t tested is about passing the page so it redirects you to the exact page:

          while($row = mysqli_fetch_array($result)){

          if(isset($_GET[‘lastUpdated’]) && $_GET[‘lastUpdated’] == $row[‘{COLUMN_NAME}’]){echo “”;}else {echo ”;}

          4th – Just modified this:

          echo “”;

          5th – On the index page I added:

          Then on tables.php I modified this so the num of elements gets stored in config file:

          $txt .= “\$db_password = ‘$password’; \n”;
          $txt .= “\$no_of_records_per_page = $numrecordsperpage; \n?>”;

          On the template page I deleted the reference to this variable since it is linking to the config file it will get that value.

          6th – This was in 1st point

          7th – I was checking this but I still haven’t done it all. I created a function that will check the value of the column and return the min max values: I guess with regular expressions and with searching string you can find the exact type maybe for example INT then search for unsigned then you can choose the min max values.

          I just checked and the input field can have attributes Min and Max so it will also force you to use a valid number, I will try to figure it out and send it to you.

          8th This is a new feature that I thought about, I want to create a DB that has many relationships, something like RESOURCE has resource ID then there is another table URL that has information and Resource ID that must be one of the existing ones, it would be awesome if that could be set up too.
          Something like this column will depend on Resources.ID, I will look at it but that I will probably not be able to accomplish since my skills are not too good.

          Thank you very much and sorry about this long text, if it is better for you send me and email and I will send it better formatted.

          Thank you very much!

  6. Peter Häggstrand

    Jan, you saved my life!

    I have a huge collection of comics that I put in to a database (nerdy as hell). Mainly for my own use so that I could easily see if I already have that nice comic I stumbled across in a used comics store… And over the years I have been tinkering with different solutions starting with Excel, than Filemaker and moving to the old Dreamweaver MX database connectors (to have it online), over to Codeigniter when Dreamweaver stopped having a graphic interface. Sigh… all I needed was an easy way to write the basic code for listing all my comics, sort it, search, update and so on…and there you came!!! THANKS!

    Now I just need to solve uploading my scanned images so I don’t have to do that manually 🙂 Any tips would be appreciated.

    1. Hello, I saw your comment, it seems like a cool idea!
      One way I can think of is probably the old way: if you have this crud maybe you could use it to upload the images into the server and save in the database something like COMIC 1 > Picture comicpicture.jpg; So basically having a column that saves the picture name. I like to use only the picture name and format not the path so instead I write the path in PHP so if you ever change the folders you will only need to upload a few lines of code not every directory in your table. I hope that makes sense.

      Another easily way of batch matching the pictures depending if each comic just has one or more images. If the comic only has one image then you could do something like uploading all the pictures with the comic ID as the name so when you retrieve the info of Comic 1 with ID:XXXX you can call your image XXXX.jpg for example.

      If each comic can have more than 1 image and you want to avoid as much programming as possible maybe you could create a folder structure like for example: pictures > XXXX (Comic ID) and inside place all the pictures.
      When you retrieve the comic information you know you can also retrieve all pictures of the pictures/XXXX/ folder and it doesn’t even matter the format because you could pull file by file and display it.

      These are the easiest ways that I can think of and you wouldn’t even need to program too much php.
      You can use Cruddiy to manage the comics DB and from there you get the ID of the comic you want to add pictures to and using your host FTP or panel upload all the pictures to the folder with the ID as name.

      I hope it makes some sense what I wrote 🙂

  7. Next features, specially :
    1. Define table relations (use for cascading deletes etc.)
    2. More specific field types (ENUM = drop-down list BOOLEAN = checkbox etc.)
    Both needs drop-down with the value=key and name as display.

  8. Just what I was looking for!

    I added this code to show page numbers


    echo " " . $number_of_results . " results - Page " . $pageno . " of " . $total_pages;

    Thank you very much Jan van.

Leave a Reply

Your email address will not be published. Required fields are marked *