{"id":29525252,"url":"https://github.com/the-an0nym/forum","last_synced_at":"2025-07-30T00:34:09.451Z","repository":{"id":303039564,"uuid":"974883763","full_name":"The-An0nym/forum","owner":"The-An0nym","description":null,"archived":false,"fork":false,"pushed_at":"2025-07-28T11:08:24.000Z","size":774,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-28T11:40:04.640Z","etag":null,"topics":["css","forum","html","infinityfree","javascript","js","mariadb","php","sql","website"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/The-An0nym.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-29T12:58:34.000Z","updated_at":"2025-07-28T11:08:28.000Z","dependencies_parsed_at":"2025-07-28T11:27:39.831Z","dependency_job_id":"42503dac-5278-4c6b-bd86-33e7dbc894be","html_url":"https://github.com/The-An0nym/forum","commit_stats":null,"previous_names":["the-an0nym/forum"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/The-An0nym/forum","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-An0nym%2Fforum","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-An0nym%2Fforum/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-An0nym%2Fforum/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-An0nym%2Fforum/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/The-An0nym","download_url":"https://codeload.github.com/The-An0nym/forum/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-An0nym%2Fforum/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267785843,"owners_count":24144122,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["css","forum","html","infinityfree","javascript","js","mariadb","php","sql","website"],"created_at":"2025-07-16T19:02:03.702Z","updated_at":"2025-07-30T00:34:09.443Z","avatar_url":"https://github.com/The-An0nym.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHP x SQL Forum\n\n**PHP** x **MariaDB** Forum (using infinityFree)\n\n**PHP** version 8.3\n\u003cbr\u003e\n**MariaDB** version 10.6\n\nThis is a personal project of mine to learn PHP. It is to be expected that:\n\n- There are bugs\n- Things are not optimized\n- There are missing features\n- It is unsafe\n- There can be massive changes at any point\n\nThis project is currently under heavy development.\n\n# Overview\n\n- [Pages](#Pages)\n- [Config file](#config-file)\n- [Database Architecture](#user-content-database-architecture)\n\n# Pages\n\n## Home (Categories)\n\nThis is `index.php` and displays a list of categories (only configurable via database)\n\n## Threads\n\nThis is `topic.php` and displays a list of threads within the chosen category. These can be created by any user and deleted by moderators and admins.\n\n## Posts\n\nThis is `thread.php` and displays all the posts within a thread. These can be created by any user and deleted by moderators and admins.\n\n## User\n\nThis is `user.php` - Every user has a public user profile page displaying their post and thread history.\n\n## Profile\n\nLocated in `profile/`, these are 3 pages: `settings.php`, `notifications.php` and `moderation.php`.\n\n# Config file\n\nThe `.config.php` file is not included for obvious reasons. This file has to be manually added and shall contain all relevant information to connect to the database. Here the pattern used in my project:\n\n```php\n\u003c?php\nreturn array(\n    \"servername\" =\u003e \"{servername}\",\n    \"username\" =\u003e \"{username}\",\n    \"password\" =\u003e \"{password}\",\n    \"dbname\" =\u003e \"{dbname}\",\n);\n```\n\n# Database Architecture\n\n![Schematic of the database for the forum](/Forum-DB-schematic.png)\n\n## General Structure\n\n### General\n\nAll `deleted` columns adhere to the following logic:\n\n| Value | Binary | Meaning                                    |\n| ----- | ------ | ------------------------------------------ |\n| 0     | 0000   | Not deleted                                |\n| 1     | 0001   | User deleted                               |\n| 2     | 0010   | Mod deleted or Auto deleted (empty thread) |\n| 4     | 0100   | Thread deleted                             |\n| 8     | 1000   | Ban deleted/Self account deleted           |\n\nWhich can be found on the `posts`, `threads` and `users` tables. All of these will be permenantly deleted after 60 days, which is executed with a 1% chance every time there is a new `mod_history` entry.\n\n### Users\n\n`handle` may only contain A-z 0-9 \\_ . and - and must be unique and between 4 and 16 characters (inclusive)\n\n`img_dir` (img in the schematic) contains the path to the image directory, stored in [src/images/profiles/](src/images/profiles/). Be careful to make sure include this directory when making backups, as the images are not saved in the database itself.\n\n`clearance` level is an integer.\n\u003cbr\u003e0 = Regular user\n\u003cbr\u003e1 = Moderator \u003csub\u003e(Can delete posts)\u003c/sub\u003e\n\u003cbr\u003e2 = Moderator \u003csub\u003e(The above and can delete threads)\u003c/sub\u003e\n\u003cbr\u003e3 = Admin \u003csub\u003e(The above and can ban users)\u003c/sub\u003e\n\u003cbr\u003e4 = Admin \u003csub\u003e(The above and can promote and demote all of the below)\u003c/sub\u003e\n\u003cbr\u003e5 = Super Admin \u003csub\u003e(The above and can promote and demote level 3 to level 4 admin. Can also view all deleted posts and deleted accounts and restore them (within the time limit))\u003c/sub\u003e\n\n### Mod_History\n\nThe `id` can be of any `post`, `thread` or `user` (indicated by the \"type\"). To avoid having polymorphic table queries, the `summary` column will contain a description (e.g. thread name or first 64 characters of the culprit's post) which, when clicked, shall reveal further information (dynamically generated via PHP).\n\nThe `type` column encodes for the following:\n\n| Value | Meaning |\n| ----- | ------- |\n| 0     | post    |\n| 1     | thread  |\n| 2     | user    |\n\nThe `judgement` column encodes for the follows:\n\n| Value | Meaning                                     |\n| ----- | ------------------------------------------- |\n| 0     | reported - unread                           |\n| 1     | reported - read                             |\n| 2     | deleted                                     |\n| 3     | deleted with threads (for banned accounts)  |\n| 4     | restored                                    |\n| 5     | restored with threads (for banned accounts) |\n| 6     | demoted                                     |\n| 7     | promoted                                    |\n\nThe `reason` column encodes for the follows:\n\n| Value | Meaning       |\n| ----- | ------------- |\n| 0     | Spam          |\n| 1     | Inappropriate |\n| 2     | Copyright     |\n| 3     | Other         |\n| 4     | Restored      |\n\n### Slugs\n\nSlugs are automatically generated for threads (for categories they need to be manually configured) and can only be edited with database access. This is to avoid SEO issues.\n\n### Subscribed\n\nThe `subscribed` table enables users to subscribe or unsubscribe form threads. If there is no entry yet, users will be auto-subscribed if they post for the first time on a thread.\n\n### Notifications\n\nNotifications are created upon:\n\n- Posting in a thread\n- User promotion\n- User Demotion\n\nAnd deleted/updated upon:\n\n- Moderation action\n- Moderation undo\n- Self deleted post\n- Expired\n\nFor clarification, users will **not** be notified when:\n\n- They post was deleted by a moderator\n- Their thread was deleted by a moderator\n- A thread they were a part of was deleted by a moderator\n\nThe `type`s are:\n\n| Value | Meaning   |\n| ----- | --------- |\n| 0     | Post      |\n| 6     | Demotion  |\n| 7     | Promotion |\n\n`post_id` and `mod_id` are stored in the `assoc_id` column. \u003cbr\u003e\nThe `deleted` makes sure that when moderators are changing the visibility of posts with undo/redo, it won't re-generate notifications but instead preserve the old one.\u003cbr\u003e\nNotifications will be automatically deleted after 60 days. This is checked by 1% chance every time a notification is updated to be flagged as deleted or not.\u003cbr\u003e\nValues 1 - 5 are reserved for future use if needed.\u003cbr\u003e\n\n## Tables\n\n(These may not be up to date and will be modified in the future)\n\n### General\n\nFor all:\n\n```SQL\nSET SQL_MODE = \"NO_AUTO_VALUE_ON_ZERO\";\nSET AUTOCOMMIT = 0;\nSTART TRANSACTION;\nSET time_zone = \"+00:00\";\n```\n\n### Users\n\n```SQL\nCREATE TABLE `users` (\n  `username` varchar(24) NOT NULL,\n  `handle` varchar(16) NOT NULL,\n  `image_dir` varchar(64) NOT NULL,\n  `posts` mediumint(8) UNSIGNED NOT NULL DEFAULT 0,\n  `threads` smallint(5) UNSIGNED NOT NULL DEFAULT 0,\n  `darkmode` tinyint(1) NOT NULL DEFAULT 0,\n  `user_id` varchar(33) NOT NULL,\n  `password` text NOT NULL,\n  `clearance` tinyint(1) UNSIGNED NOT NULL DEFAULT 0,\n  `created` datetime NOT NULL,\n  `deleted_datetime` datetime NOT NULL DEFAULT current_timestamp(),\n  `deleted` tinyint(2) UNSIGNED NOT NULL DEFAULT 0\n) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;\n```\n\n```SQL\nALTER TABLE `users`\n  ADD PRIMARY KEY (`user_id`),\n  ADD KEY `username` (`username`),\n  ADD KEY `handle` (`handle`);\nCOMMIT;\n```\n\n### Sessions\n\n```SQL\nCREATE TABLE `sessions` (\n  `user_id` varchar(33) DEFAULT NULL,\n  `ip` text DEFAULT NULL,\n  `user_agent` text DEFAULT NULL,\n  `session_id` varchar(88) DEFAULT NULL,\n  `datetime` datetime NOT NULL DEFAULT current_timestamp()\n) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;\n```\n\n### Categories\n\n```SQL\nCREATE TABLE `categories` (\n  `name` varchar(32) NOT NULL,\n  `slug` varchar(32) NOT NULL,\n  `id` varchar(33) NOT NULL,\n  `description` varchar(128) NOT NULL,\n  `created` datetime NOT NULL DEFAULT current_timestamp(),\n  `threads` mediumint(9) UNSIGNED DEFAULT 0,\n  `posts` mediumint(8) UNSIGNED DEFAULT 0\n) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;\n```\n\n```SQL\nALTER TABLE `categories`\n  ADD PRIMARY KEY (`id`),\n  ADD KEY `slug` (`slug`);\nCOMMIT;\n```\n\n### Threads\n\n```SQL\nCREATE TABLE `threads` (\n  `name` varchar(64) NOT NULL,\n  `slug` varchar(32) NOT NULL,\n  `id` varchar(33) NOT NULL,\n  `user_id` varchar(33) NOT NULL,\n  `category_id` varchar(33) NOT NULL,\n  `created` datetime NOT NULL DEFAULT current_timestamp(),\n  `deleted` tinyint(2) UNSIGNED NOT NULL DEFAULT 0,\n  `deleted_datetime` datetime NOT NULL DEFAULT current_timestamp(),\n  `posts` mediumint(8) UNSIGNED NOT NULL DEFAULT 0\n) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;\n```\n\n```SQL\nALTER TABLE `threads`\n  ADD PRIMARY KEY (`id`),\n  ADD KEY `threadcategory` (`category_id`);\nCOMMIT;\n```\n\n### Posts\n\n```SQL\nCREATE TABLE `posts` (\n  `user_id` varchar(33) NOT NULL,\n  `post_id` varchar(33) NOT NULL,\n  `content` text NOT NULL,\n  `created` datetime NOT NULL,\n  `thread_id` varchar(33) NOT NULL,\n  `edited` tinyint(1) NOT NULL DEFAULT 0,\n  `deleted` tinyint(2) UNSIGNED NOT NULL DEFAULT 0,\n  `deleted_datetime` datetime NOT NULL DEFAULT current_timestamp()\n) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;\n```\n\n```SQL\nALTER TABLE `posts`\n  ADD PRIMARY KEY (`post_id`),\n  ADD KEY `created` (`created`),\n  ADD KEY `thread` (`thread_id`);\nCOMMIT;\n```\n\n### Subscribed\n\n```SQL\nCREATE TABLE `subscribed` (\n  `thread_id` varchar(33) NOT NULL,\n  `user_id` varchar(33) NOT NULL,\n  `subscribed` tinyint(1) NOT NULL DEFAULT 1\n) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;\n```\n\n### Mod_history\n\n```SQL\nCREATE TABLE `mod_history` (\n  `mod_id` varchar(33) NOT NULL,\n  `culp_id` varchar(33) NOT NULL,\n  `id` varchar(33) NOT NULL,\n  `summary` varchar(64) NOT NULL,\n  `type` tinyint(3) UNSIGNED NOT NULL,\n  `judgement` tinyint(1) NOT NULL DEFAULT 0,\n  `sender_id` varchar(33) NOT NULL,\n  `reason` tinyint(3) UNSIGNED NOT NULL DEFAULT 0,\n  `message` text NOT NULL DEFAULT 'GENERIC',\n  `created` datetime NOT NULL DEFAULT current_timestamp()\n) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;\n```\n\n```SQL\nALTER TABLE `mod_history`\n  ADD PRIMARY KEY (`mod_id`),\n  ADD KEY `id` (`id`),\n  ADD KEY `recent` (`type`,`id`,`judgement`,`created`);\nCOMMIT;\n```\n\n### Notifications\n\n```SQL\nCREATE TABLE `notifications` (\n  `notification_id` varchar(33) NOT NULL,\n  `read` tinyint(1) NOT NULL DEFAULT 0,\n  `sender_id` varchar(33) NOT NULL,\n  `receiver_id` varchar(33) NOT NULL,\n  `type` int(1) NOT NULL DEFAULT 0,\n  `thread_id` varchar(33) DEFAULT '0',\n  `assoc_id` varchar(33) NOT NULL,\n  `deleted` tinyint(1) NOT NULL DEFAULT 0,\n  `datetime` datetime NOT NULL DEFAULT current_timestamp()\n) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthe-an0nym%2Fforum","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthe-an0nym%2Fforum","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthe-an0nym%2Fforum/lists"}