Skip to content

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.
But 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 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.


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: and MySQL and PHP are of course two peas in a pod.

Cruddiy does not follow the MVC paradigm!

Yes, look elsewhere if you need this. This is not a framework. This is a form generator.

Your code is full of dirty hacks

Sure, the generator does quite a bit of array mangling and dirty string replacement (hence the name), 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.

123 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;
          case (preg_match(“/int/i”, $columnname) ? true : false) :
          return 5;

          Next when creating the update fields I add this:

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

          $create_html [] = ‘

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

          $create_html [] .= ‘


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


          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.

  9. Sebastian Steinhauer

    I use your solution for the backend of my own private finance reporting/dashboarding app. I really like it since I hope that the simple code will last a long time before I need to create the next iteration of the application. Fewer moving parts are a good thing in my book.
    However I do have a little bit of a feature gap I see. Currently you are identifying foreign keys, and their values are available in the edit pages, but not in the index and view pages. It would be cool if there was an automatic join happening before the visible fields are selected. This way I ended up touching the sql you generate manually – which works, but I wish it wasn’t necessary.

    Awesome work. Well done.

  10. perfect for a small side project, however…

    Notice: Undefined variable: column_id in C:\wamp64\www\issue\crud\generate.php on line 267
    Call Stack
    # Time Memory Function Location
    1 0.0007 371600 {main}( ) …\generate.php:0

    No relations used when creating CRUD….

    Apache/2.4.46 (Win64) PHP/7.4.9
    Database client version: libmysql – mysqlnd 7.4.9
    PHP version: 7.4.9

  11. Hi, Thank you very much, excellent work. I have a problem with fks and dropdown, it shows only the id from the table, ex: 1 | , not gething the description column. the two table have pks and second fk. What iam doing wrong? Any step i have to do ? Thanks.

  12. Excellent script, worked perfectly.
    I had written my own CRUD but there are always little niggly problems to solve. I like what you’ve done better.
    I do have a suggestion for a future update. As it is I still have to go into PHPMyAdmin to do one operation – a copy operation that saves the new copy with a new ID, thereby inserting a new row with minimal data changes. I would love to see the same copy ability added to your script, or maybe you can simply show the code on your site and those of us who want it can insert it into your existing code.

  13. Since there’s no edit option for comments I am writing a second comment, you can merge it into the first if you want.

    I have 14 tables listed and the display of those table names is quite ugly – there are multiple rows with no space between the two rows (the blue buttons have no space between them between the rows of buttons). The buttons are centered in the page which is also rather ugly. I will be looking at the source code to see what I can do about fixing all of that.

    1. I edited the index.php file with the following code to place the many buttons in a more sensible manner. Obviously each person can build the index.php any way the want, just be sure to keep it saved because you will need it if you re-run the setup utility again. When you run the setup utility again this new customized index.php file will be overwritten. So, the solution to that is simple, just overwrite the new index.php with the the customized index.php.

      Web Site Administration




      Nav menu

      Pages Hits

      Paging Buttons






      Meta Info

      CEH Blogs

      CEH Lessons

      1. Thanks Chip! That would be nice to incorporate in Cruddiy. But I think I lost the formatting because of the WordPress comment system, maybe you could make a pull request on Github?

  14. Thank you so much. You saved me hours of work,

    FYI I did find on glitch in search. With Server version: 10.2.37-MariaDB – MariaDB Server, the CONCAT on the search pages needs to be CONCAT_WS to see records where more than one exists. Hope this helps someone else.

  15. It looks very nice. However, I get this error when updating or adding records:
    [Fri Apr 09 23:17:20.559469 2021] [php7:error] [pid 17824] [client] PHP Fatal error: Uncaught PDOException: SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect datetime value: ” for column ‘created’ at row 1 in /var/www/html/app/contacts-update.php:42\nStack trace:\n#0 /var/www/html/app/contacts-update.php(42): PDOStatement->execute()\n#1 {main}\n thrown in /var/www/html/app/contacts-update.php on line 42, referer:

    Could you please help me out with this?

    Thank you so much in advance

    1. It looks like you’re trying to add the date to a field that is of the ‘datetime’ format. MySQL expects this field to be of the format Y-m-d H:i:s (e.g. 2021-04-10 08:00:00). If it is not in the correct format MySQL will throw this error. This is not really a Cruddiy error, but a database error (Cruddiy could of course do a bit more error /type checking).

      For now: either use the correct formatting or change your database fieldtype to something else.

  16. Hi Jan and everybody..

    As a lot of folks before me already said, cruddiy is just what I was looking for.
    Great job! Very easy and direct to the task, without messing with frameworks and all that.

    I have been testing it for a little project I am doing, and I liked it very much.
    My PHP knowledge is a bit rusted and basic, but I am managing to advance on my project thanks to CRUDDY.

    I just found a couple of problems, not sure if they related to something on my setup or is something related to cruddiy.
    One of these issues I could solve touching the code, but the second one still there.

    1) As somebody already reported on the comments above, on a create record form, when retrieving values from a field coming from a foreign key, it only showed the first field (the primary key of the foreing value). To retrieve the name of the associated field (description for example) I have to comment out a line of the cruddiy code:

    file generate.php: removed the line “array_pop($row);” (appers only once on that file).
    Not sure what it does (remember my php knowledge is no deep), but with that change it finally showed me the name of the foreign field.

    2) I am not able to insert values on my tables. Only get empty values.
    For example, I have a very basic table with just two fields: id (integer, autoincrement, pk), and description (varchar).
    When I try to insert some value there, my description field stored on the database appears empty. The id (pk) with its autogenerated value is stored.
    If someone have some tip how to solve this, I would be very thankful.

    1. Thanks Ariel. I will have to look into the first mentioned problem.

      For the second, what is the actual query in the *-create.php code? Can you add items by hand / by executing this query by hand?

      1. Thanks Jan for your answer.

        ( in case the following gets messed by wordpress)

        My table name is called “estado” (status in spanish).

        mysql> describe estado;
        | Field | Type | Null | Key | Default | Extra |
        | id | int(11) | NO | PRI | NULL | auto_increment |
        | descripcion | varchar(45) | YES | | NULL | |

        The actual query on the file estado-create.php is:

        $stmt = $pdo->prepare(“INSERT INTO estado (descripcion) VALUES (?)”);

        If I run this “INSERT INTO estado (descripcion) VALUES (“test1″);” direct into my mysql console, the value is inserted.

        Thanks again Jan.

        1. Interesting! Try adding an extra field (even a dummy) somehow it works then!
          There probably is a counter index thing that is wrong when there is but one field (and one auto_increment field).

          I’ll have to debug that further.

          1. Hi again Jan.
            Thanks again for your answer.

            I tried creating a new table with the following structure:

            mysql> describe estado4;
            | Field | Type | Null | Key | Default | Extra |
            | id | varchar(45) | NO | PRI | NULL | |
            | descripcion | varchar(45) | NO | | NULL | |
            | otradescripcion | varchar(45) | NO | | NULL | |

            As you can see, this time no auto-increment, just three varchars fields.
            But still I get the same problem: the values are stored as null on the database the first time. At the second try, as it would store a duplicate value, I get a Integrity constraint violation for the duplicate (empty) id field.

  17. I found it! And fixed it:

    Thank you for pointing this out and being consistent about it, because this was a very real problem!

    I recently pulled in some large pull requests from contributors and somehow / somewhere a couple of important variables got lost… Not good.

    I have updated the code but will be checking if nothing else is missing, because I still cannot point exactly where these variables disappeared.

    1. Great job Jan.
      I already tested and it works!

      Thank you again.
      Best regards from Argentina 🙂

  18. Absolutely brilliant! Thanks.
    Getting this error in 2.2 :
    Warning: count(): Parameter must be an array or an object that implements Countable in D:\Archive\cruddiy-2.2\core\generate.php on line 3

    1. Thanks, it looks like you use Windows. I have heard this one before — also on Windows, so it must be related. But I can’t really reproduce it on my side (because I don’t have a Windows environment).

  19. Warning: count(): Parameter must be an array or an object that implements Countable in /storage/ssd4/577/16916577/public_html/cruddiy-master/core/generate.php on line 3

  20. Please fix this too… when I try to update record. I had to re-run cruddiy again to fix this.
    But I have the dreadful feeling the below syntax error will come back to bite my ass in the middle of a production server transaction.
    Please fix this too:-

    Parse error: syntax error, unexpected ‘100’ (T_LNUMBER), expecting variable (T_VARIABLE) or ‘{‘ or ‘$’ in /storage/ssd4/577/16916577/public_html/cruddiy-master/core/app/table_video_address-update.php on line 15

    Thank you my good friend.

  21. Secondly, here is table_video_address-update.php…

    false, // turn off emulation mode for “real” prepared statements
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, //turn on errors in the form of exceptions
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, //make the default fetch be an associative array
    try {
    $pdo = new PDO($dsn, $db_user, $db_password, $options);
    } catch (Exception $e) {
    exit(‘Something weird happened’);

    $vars = parse_columns(‘table_video_address’, $_POST);
    $stmt = $pdo->prepare(“UPDATE table_video_address SET id_video_address=?,video_account_url=?,video_address=?,video_title=?,video_keywords=?,video_description=?,referred_similar_channels=?,copy_competitors_keywords=?,100_plus_likes=?,100_plus_shares=?,100_plus_subscribers=?,100_plus_comments=?,is_video_15m_long=?,keywords_in_video_text=?,keywords_in_audio_text=? WHERE id_video_address=?”);

    if(!$stmt->execute([ $id_video_address,$video_account_url,$video_address,$video_title,$video_keywords,$video_description,$referred_similar_channels,$copy_competitors_keywords,$100_plus_likes,$100_plus_shares,$100_plus_subscribers,$100_plus_comments,$is_video_15m_long,$keywords_in_video_text,$keywords_in_audio_text,$id_video_address ])) {
    echo “Something went wrong. Please try again later.”;
    header(“location: error.php”);
    } else {
    $stmt = null;
    header(“location: table_video_address-read.php?id_video_address=$id_video_address”);
    } else {
    // Check existence of id parameter before processing further
    $_GET[“id_video_address”] = trim($_GET[“id_video_address”]);
    if(isset($_GET[“id_video_address”]) && !empty($_GET[“id_video_address”])){
    // Get URL parameter
    $id_video_address = trim($_GET[“id_video_address”]);

    // Prepare a select statement
    $sql = “SELECT * FROM table_video_address WHERE id_video_address = ?”;
    if($stmt = mysqli_prepare($link, $sql)){
    // Set parameters
    $param_id = $id_video_address;

    // Bind variables to the prepared statement as parameters
    if (is_int($param_id)) $__vartype = “i”;
    elseif (is_string($param_id)) $__vartype = “s”;
    elseif (is_numeric($param_id)) $__vartype = “d”;
    else $__vartype = “b”; // blob
    mysqli_stmt_bind_param($stmt, $__vartype, $param_id);

    // Attempt to execute the prepared statement
    $result = mysqli_stmt_get_result($stmt);

    if(mysqli_num_rows($result) == 1){
    /* Fetch result row as an associative array. Since the result set
    contains only one row, we don’t need to use while loop */
    $row = mysqli_fetch_array($result, MYSQLI_ASSOC);

    // Retrieve individual field value

    $id_video_address = $row[“id_video_address”];
    $video_account_url = $row[“video_account_url”];
    $video_address = $row[“video_address”];
    $video_title = $row[“video_title”];
    $video_keywords = $row[“video_keywords”];
    $video_description = $row[“video_description”];
    $referred_similar_channels = $row[“referred_similar_channels”];
    $copy_competitors_keywords = $row[“copy_competitors_keywords”];
    $100_plus_likes = $row[“100_plus_likes”];
    $100_plus_shares = $row[“100_plus_shares”];
    $100_plus_subscribers = $row[“100_plus_subscribers”];
    $100_plus_comments = $row[“100_plus_comments”];
    $is_video_15m_long = $row[“is_video_15m_long”];
    $keywords_in_video_text = $row[“keywords_in_video_text”];
    $keywords_in_audio_text = $row[“keywords_in_audio_text”];

    } else{
    // URL doesn’t contain valid id. Redirect to error page
    header(“location: error.php”);

    } else{
    echo “Oops! Something went wrong. Please try again later.”.$stmt->error;

    // Close statement

    } else{
    // URL doesn’t contain id parameter. Redirect to error page
    header(“location: error.php”);

    Update Record

    Update Record

    Please edit the input values and submit to update the record.
    <form action="” method=”post”>

    <input type="number" name="id_video_address" class="form-control" value="”>

    <input type="text" name="video_account_url" maxlength="100"class="form-control" value="”>

    <input type="text" name="video_address" maxlength="100"class="form-control" value="”>

    <input type="text" name="video_title" maxlength="50"class="form-control" value="”>

    <input type="text" name="video_keywords" maxlength="100"class="form-control" value="”>

    <input type="text" name="video_description" maxlength="255"class="form-control" value="”>

    <input type="number" name="referred_similar_channels" class="form-control" value="”>

    <input type="number" name="copy_competitors_keywords" class="form-control" value="”>

    <input type="number" name="100_plus_likes" class="form-control" value="”>

    <input type="number" name="100_plus_shares" class="form-control" value="”>

    <input type="number" name="100_plus_subscribers" class="form-control" value="”>

    <input type="number" name="100_plus_comments" class="form-control" value="”>

    <input type="number" name="is_video_15m_long" class="form-control" value="”>

    <input type="number" name="keywords_in_video_text" class="form-control" value="”>

    <input type="number" name="keywords_in_audio_text" class="form-control" value="”>

    <input type="hidden" name="id_video_address" value="”/>


  22. cruddiy was amazing , Jan
    this tools is awesome and save a lot of time.
    I have a little problem, all pages that generated by cruddiy are work like magic in my laptop. but when I had uploaded all of generated files by cruddiy into my website, there were 2 (two) generated file which can not run correctly.
    1. generated file with update function. When we wanna update the data, we used to click the pencil icon but its nothing happens and show HTTP ERROR 500
    2. generated file with view function. When we wanna view the data, we used to click the pencil icon but its nothing happens and show HTTP ERROR 500
    have any idea Jan, to solve my problem?

  23. Thanks for sharing this Jan! Unfortunately it shows an error when checking the app after the install

    ERROR: Could not able to execute SELECT * FROM databasename ORDER BY desc LIMIT 0, 10. You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘desc LIMIT 0, 10’ at line 1

    It seems like it doesn’t use a column to sort the table.

      1. Hi Jan, checked al colums, but this doesn’t solve the issue. It seems like the variable $order should have a value. When I manually enter a value it shows the table. Unfortunately in that case I am still not able to update or delete records. If you like I can send you a link by mail.

  24. Hi, this is a really great tool! I’ve found that for some reason when I generate the app that if a table only has foreign keys then it tries to order by the name of the key that it references, so if the key name isn’t the same in both tables it causes errors. It’s a quick fix in the app output files but I’m not sure what part of the generator logic would be causing the issue.

    1. I thought about this too, I see two options:
      1. The image databaserecord is a pointer to a file on the filesystem
      2. Store the image directly (as a BLOB) in the database

      Currently I have not decided what would be the better option.

  25. please provide new code for excel pdf export and also some field in update and add with dropdown list

  26. Hi, love the script, saves having to write each script, however on my localhost, everything works fine (add/edit/delete etc), but when I serve it on a paid server, I can view the list, add, delete, but can’t view or update (the page comes up with a:
    This page isn’t working is currently unable to handle this request.
    HTTP ERROR 500

    What is going wrong and how can it be fixed?

    This is the error_file:
    [23-Apr-2022 05:42:55 UTC] PHP Fatal error: Uncaught Error: Call to undefined function mysqli_stmt_get_result() in /home/XXX/public_html/setup-cruddy/app/vehicle_cleaning-update.php:111
    Stack trace:
    #0 {main}
    thrown in /home/XXX/public_html/setup-cruddy/app/vehicle_cleaning-update.php on line 111

    and line 111 is this:
    $result = mysqli_stmt_get_result($stmt);

      1. Have checked this, and they appear to be running as mysqlnd is ticked and the version running is 7.4

      2. I’ve also tried version 7.3 too which didn’t work.
        And the other issue (which may be a part of the same), is that 2 of the pages when adding, will add and go back to index, but 1 page when adding new data, when clicking submit, it too comes up wth the same error 500 page.

        1. When it does work on localhost it clearly must be something that is misconfigured on the server host side. But it’s a bit hard for me to debug without access to the error.log, so far it only indicates the missing function mysqli_stmt_get_result.

    1. Hey, awesome work! I found a few things you might want to think about for future releases:

      If there is a dash “-” in the table names, the created variable names in the code don’t work, causing errors on every page.

      If there is no primary key in the table being accessed, there are no errors during set up, but the code does not know what variable to use in the query parameter to retrieve/update/delete a specific record.

    2. You beautiful bast..d you. Perfect for xampp and as a local tool for so many projects.
      I have coded since the 90’s and little blocks of productivity magic like this make this 60yr old very happy to see and use.
      Power to your elbow brother.

    3. Hi Jan, this is a great job done by you, Congrats!!! I tried, but I have an error message (looked on many pages…) but I just don’t know how to fix it. Could you please help me?

      ERROR: Could not able to execute SELECT * FROM T_Euno_LED ORDER BY desc LIMIT 0, 25. You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘desc LIMIT 0, 25’ at line 1

      So there's no table nor data shown…

      Thank you!



    4. This a great script, thanks. One question: how can I get it to refer to my own .css after it gets ahold of the default .css? In my .css I have indented paragraphs but they don’t appear indented in the tables, but on the website no problem, of course.

        1. Thanks for the reply, when I add the small CSS to the config.php file it breaks the submit button and causes a “headers already sent” error in the log. So, that leaves me with adding the tiny bit of CSS into every one of the 74 or so files?

            1. No need to get snippy. In the app folder, there is no templates file. I added a little bit of CSS to the aforementioned file and nothing changed. (The code I add is to indent paragraphs and line-space them.) I then did a further test by increasing the font size ( a lot)–no change. I then margin-right to 50–no change. I then changed the margin-top to 50 and again, no change.

              I checked the source code of one page (blogs-read.php) and it appears the templates.php file is not being included/required by the many files for the pages. As a test, I added require_once “templates.php”; to the Include config file section of the blogs-read.php under the similar lines to require the config.php and helpers.php and the result was a blank white page. Then I removed the added line, refreshed the page, and it loaded as the original.

              1. Just to be clear – the new bit of CSS I added is this:
                .indents {
                line-height: 1.75;
                margin: 0;
                padding: 0;
                Save the file, refresh the app page with the menu buttons, press one of them (Blogs), press the View Record eye-icon and the desired CSS does not appear in the text of the blog. The blog code itself has the appropriate code and it works on my website pages with no problems from the site-wide .css file.

                Why won’t the CSS code in the templates file appear in the results pages within cruddiy? Isn’t that why it’s there? Or is it only for the actual menu/index page?

                What I expect to see is this: when viewing a record, blogs-read.php for example, I expect to see the paragraphs indented and spaced at 1.75 as specified in the templates.php file.

                1. I see. You created your own class, but do you apply the class .indents anywhere else to an HTML element in the code (e.g. templates.php file)?
                  The class definition looks fine, but it needs to be applied, since Cruddiy does not use the name ‘indents’ anywhere.

                2. As I wrote above: “The blog code itself has the appropriate code and it works on my website pages with no problems from the site-wide .css file.”
                  Meaning: yes, every paragraph has the class –
                  And when I view the webpages I see them formatted as expected, as defined by the class in my own website .css file.
                  This is the cruddiy template section:


                  .page-header h2{
                  margin-top: 0;
                  table tr td:last-child a{
                  margin-right: 5px;
                  body {
                  font-size: 14px;
                  .indents {
                  line-height: 1.75;
                  margin: 0;
                  padding: 0;

                  So, if this is there, and my individual pages have the appropriate class added to the paragraph tags, why, when I view the page in cruddy there are no indented paragraphs?

                  1. I looked at the code for the -create, -delete, -index, -read, -update files and none of them include/require the templates file. Instead they all call the bootstrap CSS within their own head section.
                    When I add a link (in those individual file’s head sections) to my website’s CSS the expected results are visible.

                    So, one has to add the link to an external stylesheet in the head section of the -index, -read, and -update files to see the changes reflected in the app.

            2. Hey Jan,

              Lovin’ your work, it’s a great tool!

              I have a question if I may; I’m getting “Notice: Undefined index: HTTPS in D:\xampp\htdocs\cruddiy\cruddiy\app\***-index.php on line 51” it’s not causing an issue just wondering why 😉

            3. Hello:
              I found your project and I like it. But, the same has 2 errors and I like your answer.
              When display the information:
              Notice: Undefined index: HTTPS in C:\xampp\htdocs\CRUD_DIY\app\autores-index.php on line 51
              When search:
              ERROR: Could not able to execute SELECT * FROM materias WHERE CONCAT_WS (descriptores) LIKE ‘%historia%’ ORDER BY id desc LIMIT 0, 10. Incorrect parameter count in the call to native function ‘CONCAT_WS’

            4. Thanks! Great work that saves users a lot of time. Best and easiest solution for my problem. The only thing missing is an export function for CSV and/or Excel for different tables. Maybe soon – I hope so?
              Thank you again!

            5. Excellent tool!

              Perfect for a simple web application with few tables that you want to make wide compatible and easy to maintain along years as is not framework version compatible.

              Just miss a more “centralized” includes, for naming, requests… But anyway almost perfect for super small projects.

              Thank you!

                1. I tried that, it didn’t help. The program isn’t creating an app folder at all, and when I make an empty app folder and an empty config.php, and give the webuser access to them, it lets me continue, but doesn’t show any tables.

            6. awesome!
              thanks for the great job done. It works quite well on my localhost, I plan to use it in my coming project.
              thanks a lot.

            7. Hi Jan,
              Brilliant !
              Wenn Du Lust hast, könnte ich Dir bei einigen Erweiterungen weiterhelfen.
              Sag einfach Bescheid.

              Beste Grüße


            8. I really love cruddiy! I use it in so many ways that you can’t imagine jejejeje. Where do you think you could continue with the next features? I ask because I would like to help you to continue it if you dont have the time. Please let me know.
              Great job. Thanks a lot! =)

            9. Here’s a bug that other users mentioned:

              Warning: Undefined array key “HTTPS” (Line 51)

              That said, it’s a great App for small projects. Thanks for it!

                1. Hi Jan,

                  Thanks for getting back. It appears in de grid page (it’s an error that has been reported before by other users and below i’ve posted the fix).

                  Best Regards,


            10. Fix:

              This line…

              $protocol=($_SERVER[‘HTTPS’] == “on” ? “https” : “http”);

              Should be replaced by this one…

              $protocol = isset($_SERVER[‘HTTPS’]) && $_SERVER[‘HTTPS’] === ‘on’ ? ‘https’ : ‘http’;

              Best Regards,


            11. Hello Jan,
              Superb work!
              This will greatly help me learn and understand how this all works.
              I got a little problem though, on every page I select to view, I got this message:
              Warning: Undefined array key “HTTPS” in C:\wamp64\www\cruddyi\app\clients-index.php on line 51
              I got 5 pages and they all have that same exact message, even though the pages display properly.
              I’m running a local server and this won’t be going on the WWW. It will be a local app only. Don’t know if this makes a difference.

              Thanks for any help you can provide.


            12. NEVERMIND my previous message.
              I’ve just read Diego’s post about the same problem and his fix.



            Leave a Reply

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