# Technical documentation — react-php-tutorial

Evidence date: 2026-10-05. Revision: `master` `d10301a` (2020-04-29).

Connection facts below are the literals in `php/db_connection.php`. They are a local tutorial default (localhost, `root`, empty password, database `login`). They are not a production configuration found in this repository.

## What this repository is

A Bitbucket Git repository with two trees and no project manifest:

- `php/` — procedural PHP scripts using `mysqli`.
- `srcHooks/` — React function components in the shape of a Create React App `src` directory.

One branch, `master`. Five commits, all authored by Uriel Balela `<uriel@overdrive.co.za>` between 2020-04-21 and 2020-04-29. Nineteen tracked files at `d10301a`. No README.

The first commit recorded a gitlink `react` → `5d85bc329cb5920e6135ff2dd78d826b8dc85920` and no `.gitmodules`. `53906de` deleted that gitlink. The submodule URL is **Unknown**.

`sonar-project.properties` and `sonarqube_scan.bat` were listed by the onboarding scan and are not in git.

## Repository layout

```text
react-php-tutorial/
  php/
    db_connection.php     mysqli_connect; die() on failure
    header.php            CORS and JSON headers
    functions.php         insert/update/select/log helpers
    signIn.php            POST JSON login
    signUp.php            POST JSON registration
    listView.php          JSON list
    delete.php            DELETE by id query parameter
    update.php            empty file
  srcHooks/
    index.js              ReactDOM.render, serviceWorker.unregister()
    index.css             CRA default body font
    App.js                router and navbar
    App.css               empty
    App.test.js           expects /learn react/i
    setupTests.js         imports @testing-library/jest-dom/extend-expect
    serviceWorker.js      CRA register/unregister helpers
    Components/
      SignIn.js
      SignUp.js
      ListView.js
      AddUserModal.js
      EditUserModal.js
```

Not in the tree: `package.json`, `public/index.html`, `composer.json`, `.gitignore`, SQL, tests for PHP, CI, Docker, `.env`.

## Runtime

| Layer | What the files assume | What git pins |
|---|---|---|
| UI | React function components, hooks, React Router v5 (`Switch`, not `Routes`) | No version |
| HTTP client | `axios` for sign-in, sign-up, and the add modal. `fetch` for the list | No version |
| Widgets | `react-bootstrap` modals. `react-bootstrap-table-next` for the list. Bootstrap  CSS imported from `node_modules/bootstrap/dist/css/bootstrap.min.css` | No version |
| Icons | Font Awesome 5 class names | Stylesheet not imported |
| Tests | `@testing-library/react` `render`, Jest `test` / `expect`, jest-dom | No config file |
| API | PHP with `mysqli_*` | No `composer.json`, no PHP version |
| Data | MySQL database `login` | No schema file |

`index.js` uses `ReactDOM.render`, which is the React 17 and earlier entry point. `serviceWorker.js` mentions `process.env.NODE_ENV` and `process.env.PUBLIC_URL`, which Create React App defines. Those files are the evidence for a CRA origin. The CRA config itself was not committed.

## How a page is assembled

`index.js` renders `<App />` into `document.getElementById('root')` under `React.StrictMode`. The HTML document that provides `root` is not in the repository.

`App.js` wraps a Bootstrap `container` in `BrowserRouter`. Routes:

| Path | Component |
|---|---|
| `/signIn` | `./Components/SignIn` |
| `/signUp` | `./Components/SignUp` |

`/` is only a `<Link>` target. There is no index route.

`ListView.js`, `AddUserModal.js`, and `EditUserModal.js` have no importer under `srcHooks/` other than themselves. They do not affect the routed tree.

`ListView.js` declares `function App` and `export default App`, so a default import would work, but none exists. It also imports `./App.css` (that path is `srcHooks/Components/App.css`, and the file is not there) and `../node_modules/bootstrap/...` (that path is `srcHooks/node_modules`, and `node_modules` is not in git). `App.js` imports Bootstrap from `../node_modules/bootstrap/...`, which is `node_modules` next to `srcHooks/`. That folder is also absent.

## API

Base URL hardcoded in the components: `http://localhost/php-react/`.

The scripts live in `php/`. Nothing in git rewrites `/php-react/` onto that directory. **Unknown / Requires Confirmation** how the author mapped it (Apache alias, vhost, or a renamed copy outside git).

| Script | Headers | Reads | Writes | Body the client would see |
|---|---|---|---|---|
| `signIn.php` | Own copy of the CORS/JSON headers. Does not include `header.php` | JSON `user_name`, `user_password` | `user.last_loggedin` on match. Insert into `tblloginuser` | `print_r` of the INSERT, then `1` or `0`. No output if either property is missing |
| `signUp.php` | Own copy of the same headers | JSON `user_name`, `user_email`, and it trims `user_password` without `isset` | Insert `user`. Then `date_created = NOW()` | `var_dump` of the payload and of the name. Then `1` if email or username exists. Otherwise `0`, the printed INSERT, and `{"success":1,"msg":"User Inserted."}` if the insert returns true |
| `listView.php` | `header.php` then `db_connection.php` | No input | None | JSON array, or an empty body if the SELECT fails |
| `delete.php` | `db_connection.php` first, then `header.php` | `$_GET['id']` | `DELETE ... LIMIT 1` | The DELETE text, then `{"success":1,"msg":"User deleted."}` or `{"success":0,"msg":"Something wrong appened, please try again."}` |
| `update.php` | None | None | None | Empty |

`header.php` sets:

- `Access-Control-Allow-Origin: *`
- `Access-Control-Allow-Headers: access`
- `Access-Control-Allow-Methods: POST`
- `Content-Type: application/json; charset=UTF-8`
- `Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With`

The methods header names POST only. `listView.php` is called with `fetch` GET. `delete.php` reads a query string. Whether a browser preflight blocks those calls depends on headers the caller adds. The plain `fetch` in `ListView.js` does not add custom headers. **Requires Confirmation** in a browser.

Client payloads:

| Caller | Call | JSON shape |
|---|---|---|
| `SignIn.js` | `axios.post(url, JSON.stringify({ name, password }))` | `name`, `password` |
| `SignUp.js` | `axios.post(url, object)` | `user_name`, `user_email`, `user_password` |
| `AddUserModal.js` | same as sign-up | same three fields |
| `EditUserModal.js` | no request | object is only logged |
| `ListView.js` | `fetch` GET | — |

`SignIn.js` stringifies before passing the body to axios. `SignUp.js` passes an object, which axios serialises as JSON. Those are different call shapes, and only the object shape uses the property names `signUp.php` reads.

No route file, no framework front controller, and no auth middleware.

## Database

`php/db_connection.php`:

| Setting | Value in source |
|---|---|
| Server | `localhost` |
| Username | `root` |
| Password | empty string |
| Database | `login` |
| API | `mysqli_connect` |
| Failure | `die("Connection failed: " . mysqli_connect_error())` |

Tables and columns referenced by SQL. Types and keys are **Unknown** because no DDL is committed.

| Table | Columns the code names | Written by |
|---|---|---|
| `user` | `id`, `username`, `email`, `password`, `date_created`, `last_loggedin` | `signUp.php` (`Insertdata` + `updateDate`), `signIn.php` (`updateDate`), `delete.php` |
| `tblloginuser` | `strResult`, `strUsername` | `signIn.php` via `Insertdata` |
| `loguser` | `refUser_id`, `log_key`, `log_oldData`, `log_newData`, `timestamp` | `SaveLog()` only. No caller |

`signIn.php` comments also name `refUserGroupID`. That identifier is not in a live query.

`Insertdata($table, $field, $data)` joins field names with commas and values with `','`, then runs `INSERT INTO $table (...) VALUES ('...')`. It `print_r`s the SQL. `signUp.php` calls it with a fourth argument `$password`. The function signature has three parameters. On PHP 8 and later, extra arguments to a user-defined function raise `ArgumentCountError`. On PHP 7 they produced a warning and were ignored. The PHP version used in 2020 is **Unknown / Requires Confirmation**.

`updateDate($field, $name)` sets `$field = NOW()` for `username = '$name'`. Callers pass the field name `last_loggedin` or `date_created` as a fixed string, and the username from the request.

`selectUser()` runs `SELECT * FROM user` but forgets `global $conn`, fetches one row, assigns local variables, and returns nothing. No caller.

`UpdateTable()` concatenates an UPDATE and stops. Comment: "not implemented yet".

`SelectData()` runs `SELECT * FROM $table` plus the condition string, echoes the SQL, and returns the rows. Comment: "works but not implement yet". No endpoint calls it.

`updatetUser()` updates `username` and `email` where `username` equals `$oldusername`. Comment: "this must be changed !!!". No caller.

## Auth

There is no authentication library and no active session.

On a password match, `signIn.php` contains a comment where `session_start()` and three `$_SESSION` keys (`username`, `id`, `userGroup`) would have been set. They are not executed.

Passwords are compared in SQL as the raw request string. Nothing in `php/` calls `password_hash` or `password_verify`.

`SaveLog()` would read `$_SESSION['id']` as `refUser_id`. With no session, that path is unused.

List and delete are reachable without a prior sign-in if the web server exposes them.

## Security observations (as implemented)

These are facts about the source, recorded so the knowledge base does not describe the tutorial as a locked-down app.

- SQL fragments are built by concatenation of request fields in `signIn.php`, `signUp.php`, `delete.php`, `Insertdata`, and `updateDate`.
- `Access-Control-Allow-Origin` is `*`.
- `delete.php` and `listView.php` have no caller check.
- Failed login distinguishes "user not found" from "incorrect password" inside `tblloginuser`. The HTTP body for both failures is `0` plus the printed INSERT.
- `Insertdata` and `delete.php` place SQL text on the HTTP response.
- `signUp.php` `var_dump`s the decoded registration body, which includes the password field when the client sent one.
- The committed database account is `root` with an empty password.

No dependency scanner, secret scanner, or security header beyond the CORS block is configured in git.

## Background work, storage, monitoring

- No queue, cron, worker, or scheduler.
- No file storage. Uploads are not implemented.
- `serviceWorker.js` can register a production service worker. `index.js` calls `unregister()`, so this app does not opt in.
- No application log file. Login attempts go to `tblloginuser` when `signIn.php` runs the insert. PHP `echo` / `var_dump` / `print_r` are the other traces.
- No metrics endpoint.

## Development and testing

No documented setup. A person would need, outside this repository:

1. A web server that executes `php/` and exposes it at `http://localhost/php-react/`.
2. A MySQL server with database `login` and the tables the queries name.
3. A React toolchain that can bundle `srcHooks` and supply the npm packages named in the imports, plus an HTML file with `id="root"`.

None of those steps are written in the repo.

The only test is `srcHooks/App.test.js`. It renders `App` and expects an element whose text matches `/learn react/i`. `App.js` renders `React-php`, `Sign In`, and `Sign Up`. The assertion does not match this UI. `setupTests.js` is the CRA jest-dom import. There is no `phpunit` configuration and no PHP test.

`App.css` is empty. `index.css` sets the CRA system font stack on `body` and a monospace stack on `code`.

## Deployment and environments

No deployment manifest, pipeline, or environment split. The only environment is the literals above: localhost PHP, localhost MySQL, and a React dev bundle that is not defined here.

`redirectToLoginPage()` sends `Location: ../index.php` and `exit()`. `index.php` is not in the repository, and no script calls the function.

## Dependency list (import and call evidence)

JavaScript modules named by source:

- `react`
- `react-dom`
- `react-router-dom`
- `axios`
- `react-bootstrap`
- `bootstrap/dist/css/bootstrap.min.css`
- `react-bootstrap-table-next`
- `@testing-library/react`
- `@testing-library/jest-dom/extend-expect`

PHP extensions named by calls:

- `mysqli`
- JSON (`json_decode`, `json_encode`)

External systems:

- MySQL on localhost
- Whatever serves `http://localhost/php-react/`

## File-to-behaviour index

| Path | Behaviour |
|---|---|
| `srcHooks/App.js` | Router shell |
| `srcHooks/index.js` | Mount and unregister the service worker |
| `srcHooks/Components/SignIn.js` | Sign-in form; posts `{name, password}` |
| `srcHooks/Components/SignUp.js` | Sign-up form; posts the three `user_*` fields |
| `srcHooks/Components/AddUserModal.js` | Modal that posts the same three fields |
| `srcHooks/Components/EditUserModal.js` | Modal that logs fields and does not POST |
| `srcHooks/Components/ListView.js` | GET list into a Bootstrap table |
| `php/signIn.php` | Plaintext match, login log, `last_loggedin` |
| `php/signUp.php` | Duplicate check, insert, `date_created` |
| `php/listView.php` | JSON users without the password field |
| `php/delete.php` | Delete by id, SQL echoed before JSON |
| `php/update.php` | Empty |
| `php/functions.php` | Helpers, most of them unused by the endpoints |
| `php/db_connection.php` | mysqli connection |
| `php/header.php` | CORS and JSON content type |
| `srcHooks/App.test.js` | Starter test that does not match `App.js` |
