├── .gitignore ├── LICENSE ├── README.md ├── app ├── .htaccess ├── Common.php ├── Config │ ├── App.php │ ├── Autoload.php │ ├── Boot │ │ ├── development.php │ │ ├── production.php │ │ └── testing.php │ ├── Cache.php │ ├── Constants.php │ ├── ContentSecurityPolicy.php │ ├── Database.php │ ├── DocTypes.php │ ├── Email.php │ ├── Encryption.php │ ├── Events.php │ ├── Exceptions.php │ ├── Filters.php │ ├── ForeignCharacters.php │ ├── Format.php │ ├── Honeypot.php │ ├── Images.php │ ├── Kint.php │ ├── Logger.php │ ├── Migrations.php │ ├── Mimes.php │ ├── Modules.php │ ├── Pager.php │ ├── Paths.php │ ├── Routes.php │ ├── Services.php │ ├── Toolbar.php │ ├── UserAgents.php │ ├── Validation.php │ └── View.php ├── Controllers │ ├── BaseController.php │ ├── Chat.php │ ├── Dashboard.php │ ├── Home.php │ ├── Server.php │ └── Users.php ├── Database │ ├── Migrations │ │ ├── .gitkeep │ │ ├── 20121031100537_add_users.php │ │ └── 2020-04-24-174346_add_connections.php │ └── Seeds │ │ └── .gitkeep ├── Filters │ ├── .gitkeep │ ├── Auth.php │ ├── Noauth.php │ └── UsersCheck.php ├── Helpers │ └── .gitkeep ├── Language │ └── .gitkeep ├── Libraries │ ├── .gitkeep │ └── Chat.php ├── Models │ ├── .gitkeep │ ├── ConnectionsModel.php │ └── UserModel.php ├── ThirdParty │ └── .gitkeep ├── Validation │ └── UserRules.php ├── Views │ ├── chat.php │ ├── dashboard.php │ ├── errors │ │ ├── cli │ │ │ ├── error_404.php │ │ │ ├── error_exception.php │ │ │ └── production.php │ │ └── html │ │ │ ├── debug.css │ │ │ ├── debug.js │ │ │ ├── error_404.php │ │ │ ├── error_exception.php │ │ │ └── production.php │ ├── login.php │ ├── profile.php │ ├── register.php │ ├── templates │ │ ├── footer.php │ │ └── header.php │ └── welcome_message.php └── index.html ├── builds ├── composer.json ├── contributing.md ├── env ├── license.txt ├── phpunit.xml.dist ├── public ├── .htaccess ├── assets │ ├── css │ │ └── style.css │ └── img │ │ ├── alex.jpg │ │ ├── jon.jpg │ │ └── mary.jpg ├── favicon.ico ├── index.php └── robots.txt ├── spark ├── tests ├── README.md ├── _support │ ├── Autoloader │ │ └── UnnamespacedClass.php │ ├── Commands │ │ ├── AbstractInfo.php │ │ └── AppInfo.php │ ├── Config │ │ ├── BadRegistrar.php │ │ ├── Registrar.php │ │ └── Routes.php │ ├── Controllers │ │ └── Popcorn.php │ ├── Database │ │ ├── Migrations │ │ │ ├── 20160428212500_Create_test_tables.php │ │ │ └── 2020-02-22-222222_example_migration.php │ │ └── Seeds │ │ │ ├── AnotherSeeder.php │ │ │ ├── CITestSeeder.php │ │ │ └── ExampleSeeder.php │ ├── DatabaseTestCase.php │ ├── Files │ │ ├── able │ │ │ ├── apple.php │ │ │ ├── fig_3.php │ │ │ └── prune_ripe.php │ │ └── baker │ │ │ └── banana.php │ ├── HTTP │ │ └── Files │ │ │ ├── CookiesHolder.txt │ │ │ └── tmp │ │ │ ├── fileA.txt │ │ │ └── fileB.txt │ ├── Images │ │ ├── EXIFsamples │ │ │ ├── down-mirrored.jpg │ │ │ ├── down.jpg │ │ │ ├── left-mirrored.jpg │ │ │ ├── left.jpg │ │ │ ├── right-mirrored.jpg │ │ │ ├── right.jpg │ │ │ ├── up-mirrored.jpg │ │ │ └── up.jpg │ │ ├── Steveston_dusk.JPG │ │ ├── ci-logo.gif │ │ ├── ci-logo.jpeg │ │ └── ci-logo.png │ ├── Language │ │ ├── SecondMockLanguage.php │ │ ├── ab-CD │ │ │ └── Allin.php │ │ ├── ab │ │ │ └── Allin.php │ │ ├── en-ZZ │ │ │ └── More.php │ │ ├── en │ │ │ ├── Allin.php │ │ │ ├── Core.php │ │ │ └── More.php │ │ └── ru │ │ │ └── Language.php │ ├── Libraries │ │ └── ConfigReader.php │ ├── Log │ │ └── Handlers │ │ │ └── TestHandler.php │ ├── MigrationTestMigrations │ │ └── Database │ │ │ └── Migrations │ │ │ ├── 2018-01-24-102300_Another_migration.py │ │ │ ├── 2018-01-24-102301_Some_migration.php │ │ │ └── 2018-01-24-102302_Another_migration.php │ ├── Models │ │ ├── EntityModel.php │ │ ├── EventModel.php │ │ ├── ExampleModel.php │ │ ├── JobModel.php │ │ ├── SecondaryModel.php │ │ ├── SimpleEntity.php │ │ ├── UserModel.php │ │ ├── ValidErrorsModel.php │ │ └── ValidModel.php │ ├── RESTful │ │ ├── Worker.php │ │ └── Worker2.php │ ├── Services.php │ ├── SessionTestCase.php │ ├── SomeEntity.php │ ├── Validation │ │ ├── TestRules.php │ │ └── uploads │ │ │ └── phpUxc0ty │ ├── View │ │ ├── SampleClass.php │ │ └── Views │ │ │ ├── simple.php │ │ │ └── simpler.php │ └── coverage.txt ├── database │ └── ExampleDatabaseTest.php ├── session │ └── ExampleSessionTest.php └── unit │ └── HealthTest.php └── writable ├── .htaccess ├── cache └── index.html ├── logs └── index.html ├── session └── index.html └── uploads └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | #------------------------- 2 | # Operating Specific Junk Files 3 | #------------------------- 4 | 5 | # OS X 6 | .DS_Store 7 | .AppleDouble 8 | .LSOverride 9 | 10 | # OS X Thumbnails 11 | ._* 12 | 13 | # Windows image file caches 14 | Thumbs.db 15 | ehthumbs.db 16 | Desktop.ini 17 | 18 | # Recycle Bin used on file shares 19 | $RECYCLE.BIN/ 20 | 21 | # Windows Installer files 22 | *.cab 23 | *.msi 24 | *.msm 25 | *.msp 26 | 27 | # Windows shortcuts 28 | *.lnk 29 | 30 | # Linux 31 | *~ 32 | 33 | # KDE directory preferences 34 | .directory 35 | 36 | # Linux trash folder which might appear on any partition or disk 37 | .Trash-* 38 | 39 | #------------------------- 40 | # Environment Files 41 | #------------------------- 42 | # These should never be under version control, 43 | # as it poses a security risk. 44 | .env 45 | .vagrant 46 | Vagrantfile 47 | 48 | #------------------------- 49 | # Temporary Files 50 | #------------------------- 51 | writable/cache/* 52 | !writable/cache/index.html 53 | 54 | writable/logs/* 55 | !writable/logs/index.html 56 | 57 | writable/session/* 58 | !writable/session/index.html 59 | 60 | writable/uploads/* 61 | !writable/uploads/index.html 62 | 63 | writable/debugbar/* 64 | 65 | php_errors.log 66 | 67 | #------------------------- 68 | # User Guide Temp Files 69 | #------------------------- 70 | user_guide_src/build/* 71 | user_guide_src/cilexer/build/* 72 | user_guide_src/cilexer/dist/* 73 | user_guide_src/cilexer/pycilexer.egg-info/* 74 | 75 | #------------------------- 76 | # Test Files 77 | #------------------------- 78 | tests/coverage* 79 | 80 | # Don't save phpunit under version control. 81 | phpunit 82 | 83 | #------------------------- 84 | # Composer 85 | #------------------------- 86 | vendor/ 87 | composer.lock 88 | 89 | #------------------------- 90 | # IDE / Development Files 91 | #------------------------- 92 | 93 | # Modules Testing 94 | _modules/* 95 | 96 | # phpenv local config 97 | .php-version 98 | 99 | # Jetbrains editors (PHPStorm, etc) 100 | .idea/ 101 | *.iml 102 | 103 | # Netbeans 104 | nbproject/ 105 | build/ 106 | nbbuild/ 107 | dist/ 108 | nbdist/ 109 | nbactions.xml 110 | nb-configuration.xml 111 | .nb-gradle/ 112 | 113 | # Sublime Text 114 | *.tmlanguage.cache 115 | *.tmPreferences.cache 116 | *.stTheme.cache 117 | *.sublime-workspace 118 | *.sublime-project 119 | .phpintel 120 | /api/ 121 | 122 | # Visual Studio Code 123 | .vscode/ 124 | 125 | /results/ 126 | /phpunit*.xml 127 | /.phpunit.*.cache 128 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CodeIgniter 4 web framework 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CodeIgniter 4 Real Time Chat Application 2 | This are the project files used in YouTube tutorial 3 | > https://www.youtube.com/watch?v=9qIIjv17IgQ 4 | 5 | ### 1. Download & Install 6 | Once cloned, open terminal and navigate inside the project folder, then run: 7 | > composer install 8 | 9 | ### 2. Setup 10 | Create a new database. DO NOT create any tables yet. Create .env file (a duplicate of 'env' sample file) and uncomment default.database block. Then also change the database connection details, after that run in your terminal: 11 | > php spark migrate 12 | 13 | This will create the tables that are required for the CodeIgniter 4 Chat Tutorial 14 | 15 | ### 3. Register users 16 | Tables in your database are empty, so you will have to create users yourself through the registration form. 17 | 18 | ### 4. Enjoy the tutorial. 19 | -------------------------------------------------------------------------------- /app/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Deny from all 6 | 7 | -------------------------------------------------------------------------------- /app/Common.php: -------------------------------------------------------------------------------- 1 | SYSPATH 50 | * `]; 51 | */ 52 | $psr4 = [ 53 | 'App' => APPPATH, // To ensure filters, etc still found, 54 | APP_NAMESPACE => APPPATH, // For custom namespace 55 | 'Config' => APPPATH . 'Config', 56 | ]; 57 | 58 | /** 59 | * ------------------------------------------------------------------- 60 | * Class Map 61 | * ------------------------------------------------------------------- 62 | * The class map provides a map of class names and their exact 63 | * location on the drive. Classes loaded in this manner will have 64 | * slightly faster performance because they will not have to be 65 | * searched for within one or more directories as they would if they 66 | * were being autoloaded through a namespace. 67 | * 68 | * Prototype: 69 | * 70 | * $Config['classmap'] = [ 71 | * 'MyClass' => '/path/to/class/file.php' 72 | * ]; 73 | */ 74 | $classmap = []; 75 | 76 | //-------------------------------------------------------------------- 77 | // Do Not Edit Below This Line 78 | //-------------------------------------------------------------------- 79 | 80 | $this->psr4 = array_merge($this->psr4, $psr4); 81 | $this->classmap = array_merge($this->classmap, $classmap); 82 | 83 | unset($psr4, $classmap); 84 | } 85 | 86 | //-------------------------------------------------------------------- 87 | 88 | } 89 | -------------------------------------------------------------------------------- /app/Config/Boot/development.php: -------------------------------------------------------------------------------- 1 | '127.0.0.1', 82 | 'port' => 11211, 83 | 'weight' => 1, 84 | 'raw' => false, 85 | ]; 86 | 87 | /* 88 | | ------------------------------------------------------------------------- 89 | | Redis settings 90 | | ------------------------------------------------------------------------- 91 | | Your Redis server can be specified below, if you are using 92 | | the Redis or Predis drivers. 93 | | 94 | */ 95 | public $redis = [ 96 | 'host' => '127.0.0.1', 97 | 'password' => null, 98 | 'port' => 6379, 99 | 'timeout' => 0, 100 | 'database' => 0, 101 | ]; 102 | 103 | /* 104 | |-------------------------------------------------------------------------- 105 | | Available Cache Handlers 106 | |-------------------------------------------------------------------------- 107 | | 108 | | This is an array of cache engine alias' and class names. Only engines 109 | | that are listed here are allowed to be used. 110 | | 111 | */ 112 | public $validHandlers = [ 113 | 'dummy' => \CodeIgniter\Cache\Handlers\DummyHandler::class, 114 | 'file' => \CodeIgniter\Cache\Handlers\FileHandler::class, 115 | 'memcached' => \CodeIgniter\Cache\Handlers\MemcachedHandler::class, 116 | 'predis' => \CodeIgniter\Cache\Handlers\PredisHandler::class, 117 | 'redis' => \CodeIgniter\Cache\Handlers\RedisHandler::class, 118 | 'wincache' => \CodeIgniter\Cache\Handlers\WincacheHandler::class, 119 | ]; 120 | } 121 | -------------------------------------------------------------------------------- /app/Config/Constants.php: -------------------------------------------------------------------------------- 1 | '', 34 | 'hostname' => 'localhost', 35 | 'username' => '', 36 | 'password' => '', 37 | 'database' => '', 38 | 'DBDriver' => 'MySQLi', 39 | 'DBPrefix' => '', 40 | 'pConnect' => false, 41 | 'DBDebug' => (ENVIRONMENT !== 'production'), 42 | 'cacheOn' => false, 43 | 'cacheDir' => '', 44 | 'charset' => 'utf8', 45 | 'DBCollat' => 'utf8_general_ci', 46 | 'swapPre' => '', 47 | 'encrypt' => false, 48 | 'compress' => false, 49 | 'strictOn' => false, 50 | 'failover' => [], 51 | 'port' => 3306, 52 | ]; 53 | 54 | /** 55 | * This database connection is used when 56 | * running PHPUnit database tests. 57 | * 58 | * @var array 59 | */ 60 | public $tests = [ 61 | 'DSN' => '', 62 | 'hostname' => '127.0.0.1', 63 | 'username' => '', 64 | 'password' => '', 65 | 'database' => ':memory:', 66 | 'DBDriver' => 'SQLite3', 67 | 'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS 68 | 'pConnect' => false, 69 | 'DBDebug' => (ENVIRONMENT !== 'production'), 70 | 'cacheOn' => false, 71 | 'cacheDir' => '', 72 | 'charset' => 'utf8', 73 | 'DBCollat' => 'utf8_general_ci', 74 | 'swapPre' => '', 75 | 'encrypt' => false, 76 | 'compress' => false, 77 | 'strictOn' => false, 78 | 'failover' => [], 79 | 'port' => 3306, 80 | ]; 81 | 82 | //-------------------------------------------------------------------- 83 | 84 | public function __construct() 85 | { 86 | parent::__construct(); 87 | 88 | // Ensure that we always set the database group to 'tests' if 89 | // we are currently running an automated test suite, so that 90 | // we don't overwrite live data on accident. 91 | if (ENVIRONMENT === 'testing') 92 | { 93 | $this->defaultGroup = 'tests'; 94 | 95 | // Under Travis-CI, we can set an ENV var named 'DB_GROUP' 96 | // so that we can test against multiple databases. 97 | if ($group = getenv('DB')) 98 | { 99 | if (is_file(TESTPATH . 'travis/Database.php')) 100 | { 101 | require TESTPATH . 'travis/Database.php'; 102 | 103 | if (! empty($dbconfig) && array_key_exists($group, $dbconfig)) 104 | { 105 | $this->tests = $dbconfig[$group]; 106 | } 107 | } 108 | } 109 | } 110 | } 111 | 112 | //-------------------------------------------------------------------- 113 | 114 | } 115 | -------------------------------------------------------------------------------- /app/Config/DocTypes.php: -------------------------------------------------------------------------------- 1 | '', 14 | 'xhtml1-strict' => '', 15 | 'xhtml1-trans' => '', 16 | 'xhtml1-frame' => '', 17 | 'xhtml-basic11' => '', 18 | 'html5' => '', 19 | 'html4-strict' => '', 20 | 'html4-trans' => '', 21 | 'html4-frame' => '', 22 | 'mathml1' => '', 23 | 'mathml2' => '', 24 | 'svg10' => '', 25 | 'svg11' => '', 26 | 'svg11-basic' => '', 27 | 'svg11-tiny' => '', 28 | 'xhtml-math-svg-xh' => '', 29 | 'xhtml-math-svg-sh' => '', 30 | 'xhtml-rdfa-1' => '', 31 | 'xhtml-rdfa-2' => '', 32 | ]; 33 | } 34 | -------------------------------------------------------------------------------- /app/Config/Email.php: -------------------------------------------------------------------------------- 1 | 0) 26 | { 27 | \ob_end_flush(); 28 | } 29 | 30 | \ob_start(function ($buffer) { 31 | return $buffer; 32 | }); 33 | } 34 | 35 | /* 36 | * -------------------------------------------------------------------- 37 | * Debug Toolbar Listeners. 38 | * -------------------------------------------------------------------- 39 | * If you delete, they will no longer be collected. 40 | */ 41 | if (ENVIRONMENT !== 'production') 42 | { 43 | Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect'); 44 | Services::toolbar()->respond(); 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /app/Config/Exceptions.php: -------------------------------------------------------------------------------- 1 | \CodeIgniter\Filters\CSRF::class, 11 | 'toolbar' => \CodeIgniter\Filters\DebugToolbar::class, 12 | 'honeypot' => \CodeIgniter\Filters\Honeypot::class, 13 | 'auth' => \App\Filters\Auth::class, 14 | 'noauth' => \App\Filters\Noauth::class, 15 | 'userscheck' => \App\Filters\UsersCheck::class, 16 | ]; 17 | 18 | // Always applied before every request 19 | public $globals = [ 20 | 'before' => [ 21 | 'userscheck' 22 | //'honeypot' 23 | // 'csrf', 24 | ], 25 | 'after' => [ 26 | 'toolbar', 27 | //'honeypot' 28 | ], 29 | ]; 30 | 31 | // Works on all of a particular HTTP method 32 | // (GET, POST, etc) as BEFORE filters only 33 | // like: 'post' => ['CSRF', 'throttle'], 34 | public $methods = []; 35 | 36 | // List filter aliases and any before/after uri patterns 37 | // that they should run on, like: 38 | // 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']], 39 | public $filters = []; 40 | } 41 | -------------------------------------------------------------------------------- /app/Config/ForeignCharacters.php: -------------------------------------------------------------------------------- 1 | \CodeIgniter\Format\JSONFormatter::class, 39 | 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, 40 | 'text/xml' => \CodeIgniter\Format\XMLFormatter::class, 41 | ]; 42 | 43 | //-------------------------------------------------------------------- 44 | 45 | /** 46 | * A Factory method to return the appropriate formatter for the given mime type. 47 | * 48 | * @param string $mime 49 | * 50 | * @return \CodeIgniter\Format\FormatterInterface 51 | */ 52 | public function getFormatter(string $mime) 53 | { 54 | if (! array_key_exists($mime, $this->formatters)) 55 | { 56 | throw new \InvalidArgumentException('No Formatter defined for mime type: ' . $mime); 57 | } 58 | 59 | $class = $this->formatters[$mime]; 60 | 61 | if (! class_exists($class)) 62 | { 63 | throw new \BadMethodCallException($class . ' is not a valid Formatter.'); 64 | } 65 | 66 | return new $class(); 67 | } 68 | 69 | //-------------------------------------------------------------------- 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/Config/Honeypot.php: -------------------------------------------------------------------------------- 1 | {label}'; 34 | } 35 | -------------------------------------------------------------------------------- /app/Config/Images.php: -------------------------------------------------------------------------------- 1 | \CodeIgniter\Images\Handlers\GDHandler::class, 29 | 'imagick' => \CodeIgniter\Images\Handlers\ImageMagickHandler::class, 30 | ]; 31 | } 32 | -------------------------------------------------------------------------------- /app/Config/Kint.php: -------------------------------------------------------------------------------- 1 | [ 88 | 89 | /* 90 | * The log levels that this handler will handle. 91 | */ 92 | 'handles' => [ 93 | 'critical', 94 | 'alert', 95 | 'emergency', 96 | 'debug', 97 | 'error', 98 | 'info', 99 | 'notice', 100 | 'warning', 101 | ], 102 | 103 | /* 104 | * The default filename extension for log files. 105 | * An extension of 'php' allows for protecting the log files via basic 106 | * scripting, when they are to be stored under a publicly accessible directory. 107 | * 108 | * Note: Leaving it blank will default to 'log'. 109 | */ 110 | 'fileExtension' => '', 111 | 112 | /* 113 | * The file system permissions to be applied on newly created log files. 114 | * 115 | * IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal 116 | * integer notation (i.e. 0700, 0644, etc.) 117 | */ 118 | 'filePermissions' => 0644, 119 | ], 120 | 121 | /** 122 | * The ChromeLoggerHandler requires the use of the Chrome web browser 123 | * and the ChromeLogger extension. Uncomment this block to use it. 124 | */ 125 | // 'CodeIgniter\Log\Handlers\ChromeLoggerHandler' => [ 126 | // /* 127 | // * The log levels that this handler will handle. 128 | // */ 129 | // 'handles' => ['critical', 'alert', 'emergency', 'debug', 130 | // 'error', 'info', 'notice', 'warning'], 131 | // ] 132 | ]; 133 | } 134 | -------------------------------------------------------------------------------- /app/Config/Migrations.php: -------------------------------------------------------------------------------- 1 | php spark migrate:create 41 | | 42 | | Typical formats: 43 | | YmdHis_ 44 | | Y-m-d-His_ 45 | | Y_m_d_His_ 46 | | 47 | */ 48 | public $timestampFormat = 'Y-m-d-His_'; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/Config/Modules.php: -------------------------------------------------------------------------------- 1 | enabled) 59 | { 60 | return false; 61 | } 62 | 63 | $alias = strtolower($alias); 64 | 65 | return in_array($alias, $this->activeExplorers); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/Config/Pager.php: -------------------------------------------------------------------------------- 1 | 'CodeIgniter\Pager\Views\default_full', 22 | 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', 23 | 'default_head' => 'CodeIgniter\Pager\Views\default_head', 24 | ]; 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Items Per Page 29 | |-------------------------------------------------------------------------- 30 | | 31 | | The default number of results shown in a single page. 32 | | 33 | */ 34 | public $perPage = 20; 35 | } 36 | -------------------------------------------------------------------------------- /app/Config/Paths.php: -------------------------------------------------------------------------------- 1 | setDefaultNamespace('App\Controllers'); 19 | $routes->setDefaultController('Users'); 20 | $routes->setDefaultMethod('index'); 21 | $routes->setTranslateURIDashes(false); 22 | $routes->set404Override(); 23 | $routes->setAutoRoute(true); 24 | 25 | /** 26 | * -------------------------------------------------------------------- 27 | * Route Definitions 28 | * -------------------------------------------------------------------- 29 | */ 30 | 31 | // We get a performance increase by specifying the default 32 | // route since we don't have to scan directories. 33 | $routes->get('/', 'Users::index', ['filter' => 'noauth']); 34 | $routes->get('logout', 'Users::logout'); 35 | $routes->match(['get','post'],'register', 'Users::register', ['filter' => 'noauth']); 36 | $routes->match(['get','post'],'profile', 'Users::profile',['filter' => 'auth']); 37 | $routes->get('dashboard', 'Dashboard::index',['filter' => 'auth']); 38 | $routes->get('chat', 'Chat::index',['filter' => 'auth']); 39 | 40 | /** 41 | * -------------------------------------------------------------------- 42 | * Additional Routing 43 | * -------------------------------------------------------------------- 44 | * 45 | * There will often be times that you need additional routing and you 46 | * need to it be able to override any defaults in this file. Environment 47 | * based routes is one such time. require() additional route files here 48 | * to make that happen. 49 | * 50 | * You will have access to the $routes object within that file without 51 | * needing to reload it. 52 | */ 53 | if (file_exists(APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php')) 54 | { 55 | require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php'; 56 | } 57 | -------------------------------------------------------------------------------- /app/Config/Services.php: -------------------------------------------------------------------------------- 1 | 'Windows 10', 18 | 'windows nt 6.3' => 'Windows 8.1', 19 | 'windows nt 6.2' => 'Windows 8', 20 | 'windows nt 6.1' => 'Windows 7', 21 | 'windows nt 6.0' => 'Windows Vista', 22 | 'windows nt 5.2' => 'Windows 2003', 23 | 'windows nt 5.1' => 'Windows XP', 24 | 'windows nt 5.0' => 'Windows 2000', 25 | 'windows nt 4.0' => 'Windows NT 4.0', 26 | 'winnt4.0' => 'Windows NT 4.0', 27 | 'winnt 4.0' => 'Windows NT', 28 | 'winnt' => 'Windows NT', 29 | 'windows 98' => 'Windows 98', 30 | 'win98' => 'Windows 98', 31 | 'windows 95' => 'Windows 95', 32 | 'win95' => 'Windows 95', 33 | 'windows phone' => 'Windows Phone', 34 | 'windows' => 'Unknown Windows OS', 35 | 'android' => 'Android', 36 | 'blackberry' => 'BlackBerry', 37 | 'iphone' => 'iOS', 38 | 'ipad' => 'iOS', 39 | 'ipod' => 'iOS', 40 | 'os x' => 'Mac OS X', 41 | 'ppc mac' => 'Power PC Mac', 42 | 'freebsd' => 'FreeBSD', 43 | 'ppc' => 'Macintosh', 44 | 'linux' => 'Linux', 45 | 'debian' => 'Debian', 46 | 'sunos' => 'Sun Solaris', 47 | 'beos' => 'BeOS', 48 | 'apachebench' => 'ApacheBench', 49 | 'aix' => 'AIX', 50 | 'irix' => 'Irix', 51 | 'osf' => 'DEC OSF', 52 | 'hp-ux' => 'HP-UX', 53 | 'netbsd' => 'NetBSD', 54 | 'bsdi' => 'BSDi', 55 | 'openbsd' => 'OpenBSD', 56 | 'gnu' => 'GNU/Linux', 57 | 'unix' => 'Unknown Unix OS', 58 | 'symbian' => 'Symbian OS', 59 | ]; 60 | 61 | // The order of this array should NOT be changed. Many browsers return 62 | // multiple browser types so we want to identify the sub-type first. 63 | public $browsers = [ 64 | 'OPR' => 'Opera', 65 | 'Flock' => 'Flock', 66 | 'Edge' => 'Spartan', 67 | 'Chrome' => 'Chrome', 68 | // Opera 10+ always reports Opera/9.80 and appends Version/ to the user agent string 69 | 'Opera.*?Version' => 'Opera', 70 | 'Opera' => 'Opera', 71 | 'MSIE' => 'Internet Explorer', 72 | 'Internet Explorer' => 'Internet Explorer', 73 | 'Trident.* rv' => 'Internet Explorer', 74 | 'Shiira' => 'Shiira', 75 | 'Firefox' => 'Firefox', 76 | 'Chimera' => 'Chimera', 77 | 'Phoenix' => 'Phoenix', 78 | 'Firebird' => 'Firebird', 79 | 'Camino' => 'Camino', 80 | 'Netscape' => 'Netscape', 81 | 'OmniWeb' => 'OmniWeb', 82 | 'Safari' => 'Safari', 83 | 'Mozilla' => 'Mozilla', 84 | 'Konqueror' => 'Konqueror', 85 | 'icab' => 'iCab', 86 | 'Lynx' => 'Lynx', 87 | 'Links' => 'Links', 88 | 'hotjava' => 'HotJava', 89 | 'amaya' => 'Amaya', 90 | 'IBrowse' => 'IBrowse', 91 | 'Maxthon' => 'Maxthon', 92 | 'Ubuntu' => 'Ubuntu Web Browser', 93 | 'Vivaldi' => 'Vivaldi', 94 | ]; 95 | 96 | public $mobiles = [ 97 | // legacy array, old values commented out 98 | 'mobileexplorer' => 'Mobile Explorer', 99 | // 'openwave' => 'Open Wave', 100 | // 'opera mini' => 'Opera Mini', 101 | // 'operamini' => 'Opera Mini', 102 | // 'elaine' => 'Palm', 103 | 'palmsource' => 'Palm', 104 | // 'digital paths' => 'Palm', 105 | // 'avantgo' => 'Avantgo', 106 | // 'xiino' => 'Xiino', 107 | 'palmscape' => 'Palmscape', 108 | // 'nokia' => 'Nokia', 109 | // 'ericsson' => 'Ericsson', 110 | // 'blackberry' => 'BlackBerry', 111 | // 'motorola' => 'Motorola' 112 | 113 | // Phones and Manufacturers 114 | 'motorola' => 'Motorola', 115 | 'nokia' => 'Nokia', 116 | 'palm' => 'Palm', 117 | 'iphone' => 'Apple iPhone', 118 | 'ipad' => 'iPad', 119 | 'ipod' => 'Apple iPod Touch', 120 | 'sony' => 'Sony Ericsson', 121 | 'ericsson' => 'Sony Ericsson', 122 | 'blackberry' => 'BlackBerry', 123 | 'cocoon' => 'O2 Cocoon', 124 | 'blazer' => 'Treo', 125 | 'lg' => 'LG', 126 | 'amoi' => 'Amoi', 127 | 'xda' => 'XDA', 128 | 'mda' => 'MDA', 129 | 'vario' => 'Vario', 130 | 'htc' => 'HTC', 131 | 'samsung' => 'Samsung', 132 | 'sharp' => 'Sharp', 133 | 'sie-' => 'Siemens', 134 | 'alcatel' => 'Alcatel', 135 | 'benq' => 'BenQ', 136 | 'ipaq' => 'HP iPaq', 137 | 'mot-' => 'Motorola', 138 | 'playstation portable' => 'PlayStation Portable', 139 | 'playstation 3' => 'PlayStation 3', 140 | 'playstation vita' => 'PlayStation Vita', 141 | 'hiptop' => 'Danger Hiptop', 142 | 'nec-' => 'NEC', 143 | 'panasonic' => 'Panasonic', 144 | 'philips' => 'Philips', 145 | 'sagem' => 'Sagem', 146 | 'sanyo' => 'Sanyo', 147 | 'spv' => 'SPV', 148 | 'zte' => 'ZTE', 149 | 'sendo' => 'Sendo', 150 | 'nintendo dsi' => 'Nintendo DSi', 151 | 'nintendo ds' => 'Nintendo DS', 152 | 'nintendo 3ds' => 'Nintendo 3DS', 153 | 'wii' => 'Nintendo Wii', 154 | 'open web' => 'Open Web', 155 | 'openweb' => 'OpenWeb', 156 | 157 | // Operating Systems 158 | 'android' => 'Android', 159 | 'symbian' => 'Symbian', 160 | 'SymbianOS' => 'SymbianOS', 161 | 'elaine' => 'Palm', 162 | 'series60' => 'Symbian S60', 163 | 'windows ce' => 'Windows CE', 164 | 165 | // Browsers 166 | 'obigo' => 'Obigo', 167 | 'netfront' => 'Netfront Browser', 168 | 'openwave' => 'Openwave Browser', 169 | 'mobilexplorer' => 'Mobile Explorer', 170 | 'operamini' => 'Opera Mini', 171 | 'opera mini' => 'Opera Mini', 172 | 'opera mobi' => 'Opera Mobile', 173 | 'fennec' => 'Firefox Mobile', 174 | 175 | // Other 176 | 'digital paths' => 'Digital Paths', 177 | 'avantgo' => 'AvantGo', 178 | 'xiino' => 'Xiino', 179 | 'novarra' => 'Novarra Transcoder', 180 | 'vodafone' => 'Vodafone', 181 | 'docomo' => 'NTT DoCoMo', 182 | 'o2' => 'O2', 183 | 184 | // Fallback 185 | 'mobile' => 'Generic Mobile', 186 | 'wireless' => 'Generic Mobile', 187 | 'j2me' => 'Generic Mobile', 188 | 'midp' => 'Generic Mobile', 189 | 'cldc' => 'Generic Mobile', 190 | 'up.link' => 'Generic Mobile', 191 | 'up.browser' => 'Generic Mobile', 192 | 'smartphone' => 'Generic Mobile', 193 | 'cellphone' => 'Generic Mobile', 194 | ]; 195 | 196 | // There are hundreds of bots but these are the most common. 197 | public $robots = [ 198 | 'googlebot' => 'Googlebot', 199 | 'msnbot' => 'MSNBot', 200 | 'baiduspider' => 'Baiduspider', 201 | 'bingbot' => 'Bing', 202 | 'slurp' => 'Inktomi Slurp', 203 | 'yahoo' => 'Yahoo', 204 | 'ask jeeves' => 'Ask Jeeves', 205 | 'fastcrawler' => 'FastCrawler', 206 | 'infoseek' => 'InfoSeek Robot 1.0', 207 | 'lycos' => 'Lycos', 208 | 'yandex' => 'YandexBot', 209 | 'mediapartners-google' => 'MediaPartners Google', 210 | 'CRAZYWEBCRAWLER' => 'Crazy Webcrawler', 211 | 'adsbot-google' => 'AdsBot Google', 212 | 'feedfetcher-google' => 'Feedfetcher Google', 213 | 'curious george' => 'Curious George', 214 | 'ia_archiver' => 'Alexa Crawler', 215 | 'MJ12bot' => 'Majestic-12', 216 | 'Uptimebot' => 'Uptimebot', 217 | ]; 218 | } 219 | -------------------------------------------------------------------------------- /app/Config/Validation.php: -------------------------------------------------------------------------------- 1 | 'CodeIgniter\Validation\Views\list', 31 | 'single' => 'CodeIgniter\Validation\Views\single', 32 | ]; 33 | 34 | //-------------------------------------------------------------------- 35 | // Rules 36 | //-------------------------------------------------------------------- 37 | } 38 | -------------------------------------------------------------------------------- /app/Config/View.php: -------------------------------------------------------------------------------- 1 | session = \Config\Services::session(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/Controllers/Chat.php: -------------------------------------------------------------------------------- 1 | table('connections'); 25 | $builder->where(['c_id >' => 0])->delete(); 26 | 27 | $server->run(); 28 | 29 | } 30 | 31 | //-------------------------------------------------------------------- 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/Controllers/Users.php: -------------------------------------------------------------------------------- 1 | request->getMethod() == 'post') { 15 | //let's do the validation here 16 | $rules = [ 17 | 'email' => 'required|min_length[6]|max_length[50]|valid_email', 18 | 'password' => 'required|min_length[8]|max_length[255]|validateUser[email,password]', 19 | ]; 20 | 21 | $errors = [ 22 | 'password' => [ 23 | 'validateUser' => 'Email or Password don\'t match' 24 | ] 25 | ]; 26 | 27 | if (! $this->validate($rules, $errors)) { 28 | $data['validation'] = $this->validator; 29 | }else{ 30 | $model = new UserModel(); 31 | 32 | $user = $model->where('email', $this->request->getVar('email')) 33 | ->first(); 34 | 35 | $this->setUserSession($user); 36 | //$session->setFlashdata('success', 'Successful Registration'); 37 | return redirect()->to('dashboard'); 38 | 39 | } 40 | } 41 | 42 | echo view('templates/header', $data); 43 | echo view('login'); 44 | echo view('templates/footer'); 45 | } 46 | 47 | private function setUserSession($user){ 48 | $data = [ 49 | 'id' => $user['id'], 50 | 'firstname' => $user['firstname'], 51 | 'lastname' => $user['lastname'], 52 | 'email' => $user['email'], 53 | 'isLoggedIn' => true, 54 | ]; 55 | 56 | session()->set($data); 57 | return true; 58 | } 59 | 60 | public function register(){ 61 | $data = []; 62 | helper(['form']); 63 | 64 | if ($this->request->getMethod() == 'post') { 65 | //let's do the validation here 66 | $rules = [ 67 | 'firstname' => 'required|min_length[3]|max_length[20]', 68 | 'lastname' => 'required|min_length[3]|max_length[20]', 69 | 'email' => 'required|min_length[6]|max_length[50]|valid_email|is_unique[users.email]', 70 | 'password' => 'required|min_length[8]|max_length[255]', 71 | 'password_confirm' => 'matches[password]', 72 | ]; 73 | 74 | if (! $this->validate($rules)) { 75 | $data['validation'] = $this->validator; 76 | }else{ 77 | $model = new UserModel(); 78 | 79 | $newData = [ 80 | 'firstname' => $this->request->getVar('firstname'), 81 | 'lastname' => $this->request->getVar('lastname'), 82 | 'email' => $this->request->getVar('email'), 83 | 'password' => $this->request->getVar('password'), 84 | ]; 85 | $model->save($newData); 86 | $session = session(); 87 | $session->setFlashdata('success', 'Successful Registration'); 88 | return redirect()->to('/'); 89 | 90 | } 91 | } 92 | 93 | 94 | echo view('templates/header', $data); 95 | echo view('register'); 96 | echo view('templates/footer'); 97 | } 98 | 99 | public function profile(){ 100 | 101 | $data = []; 102 | helper(['form']); 103 | $model = new UserModel(); 104 | 105 | if ($this->request->getMethod() == 'post') { 106 | //let's do the validation here 107 | $rules = [ 108 | 'firstname' => 'required|min_length[3]|max_length[20]', 109 | 'lastname' => 'required|min_length[3]|max_length[20]', 110 | ]; 111 | 112 | if($this->request->getPost('password') != ''){ 113 | $rules['password'] = 'required|min_length[8]|max_length[255]'; 114 | $rules['password_confirm'] = 'matches[password]'; 115 | } 116 | 117 | 118 | if (! $this->validate($rules)) { 119 | $data['validation'] = $this->validator; 120 | }else{ 121 | 122 | $newData = [ 123 | 'id' => session()->get('id'), 124 | 'firstname' => $this->request->getPost('firstname'), 125 | 'lastname' => $this->request->getPost('lastname'), 126 | ]; 127 | if($this->request->getPost('password') != ''){ 128 | $newData['password'] = $this->request->getPost('password'); 129 | } 130 | $model->save($newData); 131 | 132 | session()->setFlashdata('success', 'Successfuly Updated'); 133 | return redirect()->to('/profile'); 134 | 135 | } 136 | } 137 | 138 | $data['user'] = $model->where('id', session()->get('id'))->first(); 139 | echo view('templates/header', $data); 140 | echo view('profile'); 141 | echo view('templates/footer'); 142 | } 143 | 144 | public function logout(){ 145 | session()->destroy(); 146 | return redirect()->to('/'); 147 | } 148 | 149 | //-------------------------------------------------------------------- 150 | 151 | } 152 | -------------------------------------------------------------------------------- /app/Database/Migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/app/Database/Migrations/.gitkeep -------------------------------------------------------------------------------- /app/Database/Migrations/20121031100537_add_users.php: -------------------------------------------------------------------------------- 1 | forge->addField([ 8 | 'id' => [ 9 | 'type' => 'INT', 10 | 'unsigned' => TRUE, 11 | 'auto_increment' => TRUE 12 | ], 13 | 'firstname' => [ 14 | 'type' => 'VARCHAR', 15 | 'constraint' => '50', 16 | ], 17 | 'lastname' => [ 18 | 'type' => 'VARCHAR', 19 | 'constraint' => '50', 20 | ], 21 | 'email' => [ 22 | 'type' => 'VARCHAR', 23 | 'constraint' => '50', 24 | ], 25 | 'password' => [ 26 | 'type' => 'VARCHAR', 27 | 'constraint' => '255', 28 | ], 29 | 'created_at' => [ 30 | 'type' => 'DATETIME', 31 | // 'default' => 'current_timestamp()', 32 | ], 33 | 'updated_at' => [ 34 | 'type' => 'DATETIME', 35 | // 'default' => 'current_timestamp()', 36 | ] 37 | ]); 38 | $this->forge->addKey('id', TRUE); 39 | $this->forge->createTable('users'); 40 | } 41 | 42 | public function down() 43 | { 44 | $this->forge->dropTable('users'); 45 | } 46 | } -------------------------------------------------------------------------------- /app/Database/Migrations/2020-04-24-174346_add_connections.php: -------------------------------------------------------------------------------- 1 | forge->addField([ 10 | 'c_id' => [ 11 | 'type' => 'INT', 12 | 'unsigned' => TRUE, 13 | 'auto_increment' => TRUE 14 | ], 15 | 'c_resource_id' => [ 16 | 'type' => 'INT', 17 | ], 18 | 'c_user_id' => [ 19 | 'type' => 'INT', 20 | ], 21 | 'c_name' => [ 22 | 'type' => 'VARCHAR', 23 | 'constraint' => '50', 24 | ], 25 | 26 | ]); 27 | $this->forge->addKey('c_id', TRUE); 28 | $this->forge->createTable('connections'); 29 | } 30 | 31 | public function down() 32 | { 33 | $this->forge->dropTable('connections'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Database/Seeds/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/app/Database/Seeds/.gitkeep -------------------------------------------------------------------------------- /app/Filters/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/app/Filters/.gitkeep -------------------------------------------------------------------------------- /app/Filters/Auth.php: -------------------------------------------------------------------------------- 1 | get('isLoggedIn')){ 13 | return redirect()->to('/'); 14 | } 15 | 16 | } 17 | 18 | //-------------------------------------------------------------------- 19 | 20 | public function after(RequestInterface $request, ResponseInterface $response) 21 | { 22 | // Do something here 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/Filters/Noauth.php: -------------------------------------------------------------------------------- 1 | get('isLoggedIn')){ 13 | return redirect()->to('/dashboard'); 14 | } 15 | 16 | } 17 | 18 | //-------------------------------------------------------------------- 19 | 20 | public function after(RequestInterface $request, ResponseInterface $response) 21 | { 22 | // Do something here 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/Filters/UsersCheck.php: -------------------------------------------------------------------------------- 1 | getSegment(1) == 'users'){ 16 | if($uri->getSegment(2) == '') 17 | $segment = '/'; 18 | else 19 | $segment = '/'.$uri->getSegment(2); 20 | 21 | return redirect()->to($segment); 22 | 23 | } 24 | } 25 | 26 | //-------------------------------------------------------------------- 27 | 28 | public function after(RequestInterface $request, ResponseInterface $response) 29 | { 30 | // Do something here 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/app/Helpers/.gitkeep -------------------------------------------------------------------------------- /app/Language/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/app/Language/.gitkeep -------------------------------------------------------------------------------- /app/Libraries/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/app/Libraries/.gitkeep -------------------------------------------------------------------------------- /app/Libraries/Chat.php: -------------------------------------------------------------------------------- 1 | clients = new \SplObjectStorage; 14 | } 15 | 16 | public function onOpen(ConnectionInterface $conn) { 17 | // Store the new connection to send messages to later 18 | 19 | // ws://localhost:8080/?access_token=12312313 20 | $uriQuery = $conn->httpRequest->getUri()->getQuery(); //access_token=12312313 21 | $uriQueryArr = explode('=',$uriQuery); //$uriQueryArr[1] 22 | $userModel = new UserModel(); 23 | $conModel = new ConnectionsModel(); 24 | 25 | $user = $userModel->find($uriQueryArr[1]); 26 | $conn->user = $user; 27 | $this->clients->attach($conn); 28 | 29 | $conModel->where('c_user_id', $user['id'])->delete(); 30 | $conData = [ 31 | 'c_user_id' => $user['id'], 32 | 'c_resource_id' => $conn->resourceId, 33 | 'c_name' => $user['firstname'] 34 | ]; 35 | 36 | $conModel->save($conData); 37 | 38 | $users = $conModel->findAll(); 39 | $users = ['users' => $users]; 40 | 41 | foreach ($this->clients as $client) { 42 | $client->send(json_encode($users)); 43 | } 44 | 45 | 46 | echo "New connection! ({$conn->resourceId})\n"; 47 | } 48 | 49 | public function onMessage(ConnectionInterface $from, $msg) { 50 | $numRecv = count($this->clients) - 1; 51 | echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n" 52 | , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's'); 53 | 54 | foreach ($this->clients as $client) { 55 | if ($from !== $client) { 56 | 57 | $data = [ 58 | 'message' => $msg, 59 | 'author' => $from->user['firstname'], 60 | 'time' => date('H:i') 61 | ]; 62 | // The sender is not the receiver, send to each client connected 63 | $client->send(json_encode($data)); 64 | 65 | } 66 | } 67 | } 68 | 69 | public function onClose(ConnectionInterface $conn) { 70 | // The connection is closed, remove it, as we can no longer send it messages 71 | $this->clients->detach($conn); 72 | 73 | $conModel = new ConnectionsModel(); 74 | $conModel->where('c_resource_id', $conn->resourceId)->delete(); 75 | $users = $conModel->findAll(); 76 | $users = ['users' => $users]; 77 | foreach ($this->clients as $client) { 78 | $client->send(json_encode($users)); 79 | } 80 | 81 | echo "Connection {$conn->resourceId} has disconnected\n"; 82 | } 83 | 84 | public function onError(ConnectionInterface $conn, \Exception $e) { 85 | echo "An error has occurred: {$e->getMessage()}\n"; 86 | 87 | $conn->close(); 88 | } 89 | } -------------------------------------------------------------------------------- /app/Models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/app/Models/.gitkeep -------------------------------------------------------------------------------- /app/Models/ConnectionsModel.php: -------------------------------------------------------------------------------- 1 | passwordHash($data); 16 | $data['data']['created_at'] = date('Y-m-d H:i:s'); 17 | 18 | return $data; 19 | } 20 | 21 | protected function beforeUpdate(array $data){ 22 | $data = $this->passwordHash($data); 23 | $data['data']['updated_at'] = date('Y-m-d H:i:s'); 24 | return $data; 25 | } 26 | 27 | protected function passwordHash(array $data){ 28 | if(isset($data['data']['password'])) 29 | $data['data']['password'] = password_hash($data['data']['password'], PASSWORD_DEFAULT); 30 | 31 | return $data; 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/ThirdParty/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/app/ThirdParty/.gitkeep -------------------------------------------------------------------------------- /app/Validation/UserRules.php: -------------------------------------------------------------------------------- 1 | where('email', $data['email']) 11 | ->first(); 12 | 13 | if(!$user) 14 | return false; 15 | 16 | return password_verify($data['password'], $user['password']); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Views/chat.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Chat

6 |
7 |
8 |
9 |
    10 |
    11 |
    12 |
    13 |
    14 |
    15 |
    16 |
    17 |
    18 | 19 |
    20 |
    21 |
    22 | 23 |
    24 |
    25 |
    26 |
    27 |
    28 |
    29 |
    30 |
    31 | 32 | 33 | -------------------------------------------------------------------------------- /app/Views/dashboard.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |

    Hello, get('firstname') ?>

    5 |
    6 |
    7 |
    8 | -------------------------------------------------------------------------------- /app/Views/errors/cli/error_404.php: -------------------------------------------------------------------------------- 1 | 4 | Message: 5 | Filename: getFile(), "\n"; ?> 6 | Line Number: getLine(); ?> 7 | 8 | 9 | 10 | Backtrace: 11 | getTrace() as $error): ?> 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/Views/errors/cli/production.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 Page Not Found 6 | 7 | 70 | 71 | 72 |
    73 |

    404 - File Not Found

    74 | 75 |

    76 | 77 | 78 | 79 | Sorry! Cannot seem to find the page you were looking for. 80 | 81 |

    82 |
    83 | 84 | 85 | -------------------------------------------------------------------------------- /app/Views/errors/html/production.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Whoops! 8 | 9 | 12 | 13 | 14 | 15 |
    16 | 17 |

    Whoops!

    18 | 19 |

    We seem to have hit a snag. Please try again later...

    20 | 21 |
    22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/Views/login.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |

    Login

    6 |
    7 | get('success')): ?> 8 | 11 | 12 |
    13 |
    14 | 15 | 16 |
    17 |
    18 | 19 | 20 |
    21 | 22 |
    23 | 26 |
    27 | 28 |
    29 |
    30 | 31 |
    32 | 35 |
    36 |
    37 |
    38 |
    39 |
    40 |
    41 | -------------------------------------------------------------------------------- /app/Views/profile.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |

    6 |
    7 | get('success')): ?> 8 | 11 | 12 |
    13 |
    14 |
    15 |
    16 | 17 | 18 |
    19 |
    20 |
    21 |
    22 | 23 | 24 |
    25 |
    26 |
    27 |
    28 | 29 | 30 |
    31 |
    32 |
    33 |
    34 | 35 | 36 |
    37 |
    38 |
    39 |
    40 | 41 | 42 |
    43 |
    44 | 45 |
    46 | 49 |
    50 | 51 |
    52 | 53 |
    54 |
    55 | 56 |
    57 | 58 |
    59 |
    60 |
    61 |
    62 |
    63 |
    64 | -------------------------------------------------------------------------------- /app/Views/register.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |

    Register

    6 |
    7 |
    8 |
    9 |
    10 |
    11 | 12 | 13 |
    14 |
    15 |
    16 |
    17 | 18 | 19 |
    20 |
    21 |
    22 |
    23 | 24 | 25 |
    26 |
    27 |
    28 |
    29 | 30 | 31 |
    32 |
    33 |
    34 |
    35 | 36 | 37 |
    38 |
    39 | 40 |
    41 | 44 |
    45 | 46 |
    47 | 48 |
    49 |
    50 | 51 |
    52 | 55 |
    56 |
    57 |
    58 |
    59 |
    60 |
    61 | -------------------------------------------------------------------------------- /app/Views/templates/footer.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/Views/templates/header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Ci4 WebSocket Chat 9 | 10 | 11 | 12 | 15 | 52 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

    Directory access is forbidden.

    9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /builds: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 'vcs', 67 | 'url' => GITHUB_URL, 68 | ]; 69 | } 70 | 71 | // Define the "require" 72 | $array['require']['codeigniter4/codeigniter4'] = 'dev-develop'; 73 | unset($array['require']['codeigniter4/framework']); 74 | } 75 | 76 | // Release 77 | else 78 | { 79 | // Clear 'minimum-stability' 80 | unset($array['minimum-stability']); 81 | 82 | // If the repo is configured then clear it 83 | if (isset($array['repositories'])) 84 | { 85 | // Check for the CodeIgniter repo 86 | foreach ($array['repositories'] as $i => $repository) 87 | { 88 | if ($repository['url'] == GITHUB_URL) 89 | { 90 | unset($array['repositories'][$i]); 91 | break; 92 | } 93 | } 94 | if (empty($array['repositories'])) 95 | { 96 | unset($array['repositories']); 97 | } 98 | } 99 | 100 | // Define the "require" 101 | $array['require']['codeigniter4/framework'] = LATEST_RELEASE; 102 | unset($array['require']['codeigniter4/codeigniter4']); 103 | } 104 | 105 | // Write out a new composer.json 106 | file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES) . PHP_EOL); 107 | $modified[] = $file; 108 | } 109 | else 110 | { 111 | echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL; 112 | } 113 | } 114 | else 115 | { 116 | echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL; 117 | } 118 | } 119 | 120 | // Paths config and PHPUnit XMLs 121 | $files = [ 122 | __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php', 123 | __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml.dist', 124 | __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml', 125 | ]; 126 | 127 | foreach ($files as $file) 128 | { 129 | if (is_file($file)) 130 | { 131 | $contents = file_get_contents($file); 132 | 133 | // Development 134 | if ($dev) 135 | { 136 | $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents); 137 | } 138 | 139 | // Release 140 | else 141 | { 142 | $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents); 143 | } 144 | 145 | file_put_contents($file, $contents); 146 | $modified[] = $file; 147 | } 148 | } 149 | 150 | if (empty($modified)) 151 | { 152 | echo 'No files modified' . PHP_EOL; 153 | } 154 | else 155 | { 156 | echo 'The following files were modified:' . PHP_EOL; 157 | foreach ($modified as $file) 158 | { 159 | echo " * {$file}" . PHP_EOL; 160 | } 161 | echo 'Run `composer update` to sync changes with your vendor folder' . PHP_EOL; 162 | } 163 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codeigniter4/appstarter", 3 | "type": "project", 4 | "description": "CodeIgniter4 starter app", 5 | "homepage": "https://codeigniter.com", 6 | "license": "MIT", 7 | "require": { 8 | "php": ">=7.2", 9 | "codeigniter4/framework": "^4", 10 | "cboden/ratchet": "^0.4.2" 11 | }, 12 | "require-dev": { 13 | "mikey179/vfsstream": "1.6.*", 14 | "phpunit/phpunit": "8.5.*" 15 | }, 16 | "autoload-dev": { 17 | "psr-4": { 18 | "Tests\\Support\\": "tests/_support" 19 | } 20 | }, 21 | "scripts": { 22 | "test": "phpunit", 23 | "post-update-cmd": [ 24 | "@composer dump-autoload" 25 | ] 26 | }, 27 | "support": { 28 | "forum": "http://forum.codeigniter.com/", 29 | "source": "https://github.com/codeigniter4/CodeIgniter4", 30 | "slack": "https://codeigniterchat.slack.com" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to CodeIgniter4 2 | 3 | 4 | ## Contributions 5 | 6 | We expect all contributions to conform to our [style guide](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/styleguide.rst), be commented (inside the PHP source files), 7 | be documented (in the [user guide](https://codeigniter4.github.io/userguide/)), and unit tested (in the [test folder](https://github.com/codeigniter4/CodeIgniter4/tree/develop/tests)). 8 | There is a [Contributing to CodeIgniter](./contributing/README.rst) section in the repository which describes the contribution process; this page is an overview. 9 | 10 | Note, we expect all code changes or bug-fixes to be accompanied by one or more tests added to our test suite to prove the code works. If pull requests are not accompanied by relevant tests, they will likely be closed. Since we are a team of volunteers, we don't have any more time to work on the framework than you do. Please make it as painless for your contributions to be included as possible. If you need help with getting tests running on your local machines, ask for help on the forums. We would be happy to help out. 11 | 12 | The [Open Source Guide](https://opensource.guide/) is a good first read for those new to contributing to open source! 13 | ## Issues 14 | 15 | Issues are a quick way to point out a bug. If you find a bug or documentation error in CodeIgniter then please make sure that: 16 | 17 | 1. There is not already an open [Issue](https://github.com/codeigniter4/CodeIgniter4/issues) 18 | 2. The Issue has not already been fixed (check the develop branch or look for [closed Issues](https://github.com/codeigniter4/CodeIgniter4/issues?q=is%3Aissue+is%3Aclosed)) 19 | 3. It's not something really obvious that you can fix yourself 20 | 21 | Reporting Issues is helpful, but an even [better approach](./contributing/workflow.rst) is to send a [Pull Request](https://help.github.com/en/articles/creating-a-pull-request), which is done by [Forking](https://help.github.com/en/articles/fork-a-repo) the main repository and making a [Commit](https://help.github.com/en/desktop/contributing-to-projects/committing-and-reviewing-changes-to-your-project) to your own copy of the project. This will require you to use the version control system called [Git](https://git-scm.com/). 22 | 23 | ## Guidelines 24 | 25 | Before we look into how to contribute to CodeIgniter4, here are some guidelines. If your Pull Requests fail 26 | to pass these guidelines, they will be declined, and you will need to re-submit 27 | when you’ve made the changes. This might sound a bit tough, but it is required 28 | for us to maintain the quality of the codebase. 29 | 30 | ### PHP Style 31 | 32 | All code must meet the [Style Guide](./contributing/styleguide.rst). 33 | This makes certain that all submitted code is of the same format as the existing code and ensures that the codebase will be as readable as possible. 34 | 35 | ### Documentation 36 | 37 | If you change anything that requires a change to documentation, then you will need to add to the documentation. New classes, methods, parameters, changing default values, etc. are all changes that require a change to documentation. Also, the [changelog](https://codeigniter4.github.io/CodeIgniter4/changelogs/index.html) must be updated for every change, and [PHPDoc](https://github.com/codeigniter4/CodeIgniter4/blob/develop/phpdoc.dist.xml) blocks must be maintained. 38 | 39 | ### Compatibility 40 | 41 | CodeIgniter4 requires [PHP 7.2](https://php.net/releases/7_2_0.php). 42 | 43 | ### Branching 44 | 45 | CodeIgniter4 uses the [Git-Flow](http://nvie.com/posts/a-successful-git-branching-model/) branching model which requires all 46 | Pull Requests to be sent to the "develop" branch; this is where the next planned version will be developed. 47 | The "master" branch will always contain the latest stable version and is kept clean so a "hotfix" (e.g. an 48 | emergency security patch) can be applied to the "master" branch to create a new version, without worrying 49 | about other features holding it up. For this reason, all commits need to be made to the "develop" branch, 50 | and any sent to the "master" branch will be closed automatically. If you have multiple changes to submit, 51 | please place all changes into their own branch on your fork. 52 | 53 | **One thing at a time:** A pull request should only contain one change. That does not mean only one commit, 54 | but one change - however many commits it took. The reason for this is that if you change X and Y, 55 | but send a pull request for both at the same time, we might really want X but disagree with Y, 56 | meaning we cannot merge the request. Using the Git-Flow branching model you can create new 57 | branches for both of these features and send two requests. 58 | 59 | A reminder: **please use separate branches for each of your PRs** - it will make it easier for you to keep changes separate from 60 | each other and from whatever else you are doing with your repository! 61 | 62 | ### Signing 63 | 64 | You must [GPG-sign](./contributing/signing.rst) your work, certifying that you either wrote the work or otherwise have the right to pass it on to an open-source project. This is *not* just a "signed-off-by" commit, but instead, a digitally signed one. 65 | 66 | ## How-to Guide 67 | 68 | The best way to contribute is to fork the CodeIgniter4 repository, and "clone" that to your development area. That sounds like some jargon, but "forking" on GitHub means "making a copy of that repo to your account" and "cloning" means "copying that code to your environment so you can work on it". 69 | 70 | 1. Set up Git ([Windows](https://git-scm.com/download/win), [Mac](https://git-scm.com/download/mac), & [Linux](https://git-scm.com/download/linux)). 71 | 2. Go to the [CodeIgniter4 repository](https://github.com/codeigniter4/CodeIgniter4). 72 | 3. [Fork](https://help.github.com/en/articles/fork-a-repo) it (to your Github account). 73 | 4. [Clone](https://help.github.com/en/articles/cloning-a-repository) your CodeIgniter repository: `git@github.com:\/CodeIgniter4.git` 74 | 5. Create a new [branch](https://help.github.com/en/articles/about-branches) in your project for each set of changes you want to make. 75 | 6. Fix existing bugs on the [Issue tracker](https://github.com/codeigniter4/CodeIgniter4/issues) after confirming that no one else is working on them. 76 | 7. [Commit](https://help.github.com/en/desktop/contributing-to-projects/committing-and-reviewing-changes-to-your-project) the changed files in your contribution branch. 77 | 8. [Push](https://help.github.com/en/articles/pushing-to-a-remote) your contribution branch to your fork. 78 | 9. Send a [pull request](http://help.github.com/send-pull-requests/). 79 | 80 | The codebase maintainers will now be alerted to the submission and someone from the team will respond. If your change fails to meet the guidelines, it will be rejected or feedback will be provided to help you improve it. 81 | 82 | Once the maintainer handling your pull request is satisfied with it they will approve the pull request and merge it into the "develop" branch; your patch will now be part of the next release! 83 | 84 | ### Keeping your fork up-to-date 85 | 86 | Unlike systems like Subversion, Git can have multiple remotes. A remote is the name for the URL of a Git repository. By default, your fork will have a remote named "origin", which points to your fork, but you can add another remote named "codeigniter", which points to `git://github.com/codeigniter4/CodeIgniter4.git`. This is a read-only remote, but you can pull from this develop branch to update your own. 87 | 88 | If you are using the command-line, you can do the following to update your fork to the latest changes: 89 | 90 | 1. `git remote add codeigniter git://github.com/codeigniter4/CodeIgniter4.git` 91 | 2. `git pull codeigniter develop` 92 | 3. `git push origin develop` 93 | 94 | Your fork is now up to date. This should be done regularly and, at the least, before you submit a pull request. 95 | -------------------------------------------------------------------------------- /env: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------- 2 | # Example Environment Configuration file 3 | # 4 | # This file can be used as a starting point for your own 5 | # custom .env files, and contains most of the possible settings 6 | # available in a default install. 7 | # 8 | # By default, all of the settings are commented out. If you want 9 | # to override the setting, you must un-comment it by removing the '#' 10 | # at the beginning of the line. 11 | #-------------------------------------------------------------------- 12 | 13 | #-------------------------------------------------------------------- 14 | # ENVIRONMENT 15 | #-------------------------------------------------------------------- 16 | 17 | # CI_ENVIRONMENT = production 18 | 19 | #-------------------------------------------------------------------- 20 | # APP 21 | #-------------------------------------------------------------------- 22 | 23 | # app.baseURL = '' 24 | # app.forceGlobalSecureRequests = false 25 | 26 | # app.sessionDriver = 'CodeIgniter\Session\Handlers\FileHandler' 27 | # app.sessionCookieName = 'ci_session' 28 | # app.sessionSavePath = NULL 29 | # app.sessionMatchIP = false 30 | # app.sessionTimeToUpdate = 300 31 | # app.sessionRegenerateDestroy = false 32 | 33 | # app.cookiePrefix = '' 34 | # app.cookieDomain = '' 35 | # app.cookiePath = '/' 36 | # app.cookieSecure = false 37 | # app.cookieHTTPOnly = false 38 | 39 | # app.CSRFProtection = false 40 | # app.CSRFTokenName = 'csrf_test_name' 41 | # app.CSRFCookieName = 'csrf_cookie_name' 42 | # app.CSRFExpire = 7200 43 | # app.CSRFRegenerate = true 44 | # app.CSRFExcludeURIs = [] 45 | 46 | # app.CSPEnabled = false 47 | 48 | #-------------------------------------------------------------------- 49 | # DATABASE 50 | #-------------------------------------------------------------------- 51 | 52 | # database.default.hostname = localhost 53 | # database.default.database = ci4 54 | # database.default.username = root 55 | # database.default.password = root 56 | # database.default.DBDriver = MySQLi 57 | 58 | # database.tests.hostname = localhost 59 | # database.tests.database = ci4 60 | # database.tests.username = root 61 | # database.tests.password = root 62 | # database.tests.DBDriver = MySQLi 63 | 64 | #-------------------------------------------------------------------- 65 | # CONTENT SECURITY POLICY 66 | #-------------------------------------------------------------------- 67 | 68 | # contentsecuritypolicy.reportOnly = false 69 | # contentsecuritypolicy.defaultSrc = 'none' 70 | # contentsecuritypolicy.scriptSrc = 'self' 71 | # contentsecuritypolicy.styleSrc = 'self' 72 | # contentsecuritypolicy.imageSrc = 'self' 73 | # contentsecuritypolicy.base_uri = null 74 | # contentsecuritypolicy.childSrc = null 75 | # contentsecuritypolicy.connectSrc = 'self' 76 | # contentsecuritypolicy.fontSrc = null 77 | # contentsecuritypolicy.formAction = null 78 | # contentsecuritypolicy.frameAncestors = null 79 | # contentsecuritypolicy.mediaSrc = null 80 | # contentsecuritypolicy.objectSrc = null 81 | # contentsecuritypolicy.pluginTypes = null 82 | # contentsecuritypolicy.reportURI = null 83 | # contentsecuritypolicy.sandbox = false 84 | # contentsecuritypolicy.upgradeInsecureRequests = false 85 | 86 | #-------------------------------------------------------------------- 87 | # HONEYPOT 88 | #-------------------------------------------------------------------- 89 | 90 | # honeypot.hidden = 'true' 91 | # honeypot.label = 'Fill This Field' 92 | # honeypot.name = 'honeypot' 93 | # honeypot.template = '' 94 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2019 British Columbia Institute of Technology 4 | Copyright (c) 2019-2020 CodeIgniter Foundation 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests 15 | 16 | 17 | 18 | 19 | 20 | ./app 21 | 22 | ./app/Views 23 | ./app/Config/Routes.php 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | # Disable directory browsing 2 | Options All -Indexes 3 | 4 | # ---------------------------------------------------------------------- 5 | # Rewrite engine 6 | # ---------------------------------------------------------------------- 7 | 8 | # Turning on the rewrite engine is necessary for the following rules and features. 9 | # FollowSymLinks must be enabled for this to work. 10 | 11 | Options +FollowSymlinks 12 | RewriteEngine On 13 | 14 | # If you installed CodeIgniter in a subfolder, you will need to 15 | # change the following line to match the subfolder you need. 16 | # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase 17 | # RewriteBase / 18 | 19 | # Redirect Trailing Slashes... 20 | RewriteCond %{REQUEST_FILENAME} !-d 21 | RewriteRule ^(.*)/$ /$1 [L,R=301] 22 | 23 | # Rewrite "www.example.com -> example.com" 24 | RewriteCond %{HTTPS} !=on 25 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 26 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 27 | 28 | # Checks to see if the user is attempting to access a valid file, 29 | # such as an image or css document, if this isn't true it sends the 30 | # request to the front controller, index.php 31 | RewriteCond %{REQUEST_FILENAME} !-f 32 | RewriteCond %{REQUEST_FILENAME} !-d 33 | RewriteRule ^(.*)$ index.php/$1 [L] 34 | 35 | # Ensure Authorization header is passed along 36 | RewriteCond %{HTTP:Authorization} . 37 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 38 | 39 | 40 | 41 | # If we don't have mod_rewrite installed, all 404's 42 | # can be sent to index.php, and everything works as normal. 43 | ErrorDocument 404 index.php 44 | 45 | 46 | # Disable server signature start 47 | ServerSignature Off 48 | # Disable server signature end 49 | -------------------------------------------------------------------------------- /public/assets/css/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-color: #e1e1e1; 3 | } 4 | .form-wrapper{ 5 | border-radius: 7px; 6 | } 7 | .form-wrapper label{ 8 | font-weight: bold; 9 | } 10 | .errors li{ 11 | list-style: none; 12 | width: 100%; 13 | text-align: center; 14 | } 15 | .errors ul{ 16 | padding-left: 0; 17 | margin-bottom: 0; 18 | } 19 | .message-holder { 20 | border: 1px solid #ccc; 21 | border-radius: 4px; 22 | overflow-x: hidden; 23 | overflow-y: auto; 24 | height: 400px; 25 | margin-bottom: 20px; 26 | padding-top: 10px; 27 | padding-bottom: 10px; 28 | } 29 | .msg-item { 30 | overflow: hidden; 31 | clear: both; 32 | margin-bottom: 12px; 33 | padding-top: 10px; 34 | border-radius: 4px; 35 | padding-bottom: 10px; 36 | } 37 | .msg-text { 38 | padding-left: 70px; 39 | padding-top: 5px; 40 | line-height: 19px; 41 | padding-right: 70px; 42 | } 43 | .msg-img { 44 | width: 60px; 45 | margin: 0 10px; 46 | } 47 | .author{ 48 | font-weight: bold; 49 | } 50 | 51 | .msg-item p{ 52 | margin:0; 53 | } 54 | 55 | .msg-item .time { 56 | font-size: 10px; 57 | } 58 | .msg-item.left-msg { 59 | background: #0e85a0; 60 | color: #fff; 61 | } 62 | .msg-item.right-msg { 63 | background: #444; 64 | color: #fff; 65 | } 66 | .time { 67 | color: #fff; 68 | opacity: 0.8;; 69 | 70 | } 71 | .left-msg .msg-img{ 72 | float: left; 73 | } 74 | .right-msg{ 75 | text-align: right; 76 | } 77 | .right-msg .msg-img{ 78 | float: right; 79 | } 80 | @media (max-width: 768px){ 81 | .form-wrapper .text-right{ 82 | text-align: center !important; 83 | } 84 | 85 | .form-wrapper .btn-primary{ 86 | display: block; 87 | margin: 0 auto; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /public/assets/img/alex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/public/assets/img/alex.jpg -------------------------------------------------------------------------------- /public/assets/img/jon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/public/assets/img/jon.jpg -------------------------------------------------------------------------------- /public/assets/img/mary.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/public/assets/img/mary.jpg -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexlancer/Codeigniter-4-Chat-Tutorial/e90ddda1f94369adb50009af454b2ab625d88f73/public/favicon.ico -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | systemDirectory, '/ ') . '/bootstrap.php'; 37 | 38 | /* 39 | *--------------------------------------------------------------- 40 | * LAUNCH THE APPLICATION 41 | *--------------------------------------------------------------- 42 | * Now that everything is setup, it's time to actually fire 43 | * up the engines and make this app do its thang. 44 | */ 45 | $app->run(); 46 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /spark: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | systemDirectory, '/ ') . '/bootstrap.php'; 45 | 46 | // Grab our Console 47 | $console = new \CodeIgniter\CLI\Console($app); 48 | 49 | // We want errors to be shown when using it from the CLI. 50 | error_reporting(-1); 51 | ini_set('display_errors', 1); 52 | 53 | // Show basic information before we do anything else. 54 | $console->showHeader(); 55 | 56 | // fire off the command in the main framework. 57 | $response = $console->run(); 58 | if ($response->getStatusCode() >= 300) 59 | { 60 | exit($response->getStatusCode()); 61 | } 62 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Running Application Tests 2 | 3 | This is the quick-start to CodeIgniter testing. Its intent is to describe what 4 | it takes to set up your application and get it ready to run unit tests. 5 | It is not intended to be a full description of the test features that you can 6 | use to test your application. Those details can be found in the documentation. 7 | 8 | ## Resources 9 | * [CodeIgniter 4 User Guide on Testing](https://codeigniter4.github.io/userguide/testing/index.html) 10 | * [PHPUnit docs](https://phpunit.readthedocs.io/en/8.3/index.html) 11 | 12 | ## Requirements 13 | 14 | It is recommended to use the latest version of PHPUnit. At the time of this 15 | writing we are running version 8.5.2. Support for this has been built into the 16 | **composer.json** file that ships with CodeIgniter and can easily be installed 17 | via [Composer](https://getcomposer.org/) if you don't already have it installed globally. 18 | 19 | > composer install 20 | 21 | If running under OS X or Linux, you can create a symbolic link to make running tests a touch nicer. 22 | 23 | > ln -s ./vendor/bin/phpunit ./phpunit 24 | 25 | You also need to install [XDebug](https://xdebug.org/index.php) in order 26 | for code coverage to be calculated successfully. 27 | 28 | ## Setting Up 29 | 30 | A number of the tests use a running database. 31 | In order to set up the database edit the details for the `tests` group in 32 | **app/Config/Database.php** or **phpunit.xml**. Make sure that you provide a database engine 33 | that is currently running on your machine. More details on a test database setup are in the 34 | *Docs>>Testing>>Testing Your Database* section of the documentation. 35 | 36 | If you want to run the tests without using live database you can 37 | exclude @DatabaseLive group. Or make a copy of **phpunit.dist.xml** - 38 | call it **phpunit.xml** - and comment out the named "database". This will make 39 | the tests run quite a bit faster. 40 | 41 | ## Running the tests 42 | 43 | The entire test suite can be run by simply typing one command-line command from the main directory. 44 | 45 | > ./phpunit 46 | 47 | You can limit tests to those within a single test directory by specifying the 48 | directory name after phpunit. 49 | 50 | > ./phpunit app/Models 51 | 52 | ## Generating Code Coverage 53 | 54 | To generate coverage information, including HTML reports you can view in your browser, 55 | you can use the following command: 56 | 57 | > ./phpunit --colors --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m 58 | 59 | This runs all of the tests again collecting information about how many lines, 60 | functions, and files are tested. It also reports the percentage of the code that is covered by tests. 61 | It is collected in two formats: a simple text file that provides an overview as well 62 | as a comprehensive collection of HTML files that show the status of every line of code in the project. 63 | 64 | The text file can be found at **tests/coverage.txt**. 65 | The HTML files can be viewed by opening **tests/coverage/index.html** in your favorite browser. 66 | 67 | ## PHPUnit XML Configuration 68 | 69 | The repository has a ``phpunit.xml.dist`` file in the project root that's used for 70 | PHPUnit configuration. This is used to provide a default configuration if you 71 | do not have your own configuration file in the project root. 72 | 73 | The normal practice would be to copy ``phpunit.xml.dist`` to ``phpunit.xml`` 74 | (which is git ignored), and to tailor it as you see fit. 75 | For instance, you might wish to exclude database tests, or automatically generate 76 | HTML code coverage reports. 77 | 78 | ## Test Cases 79 | 80 | Every test needs a *test case*, or class that your tests extend. CodeIgniter 4 81 | provides a few that you may use directly: 82 | * `CodeIgniter\Test\CIUnitTestCase` - for basic tests with no other service needs 83 | * `CodeIgniter\Test\CIDatabaseTestCase` - for tests that need database access 84 | 85 | Most of the time you will want to write your own test cases to hold functions and services 86 | common to your test suites. 87 | 88 | ## Creating Tests 89 | 90 | All tests go in the **tests/** directory. Each test file is a class that extends a 91 | **Test Case** (see above) and contains methods for the individual tests. These method 92 | names must start with the word "test" and should have descriptive names for precisely what 93 | they are testing: 94 | `testUserCanModifyFile()` `testOutputColorMatchesInput()` `testIsLoggedInFailsWithInvalidUser()` 95 | 96 | Writing tests is an art, and there are many resources available to help learn how. 97 | Review the links above and always pay attention to your code coverage. 98 | 99 | ### Database Tests 100 | 101 | Tests can include migrating, seeding, and testing against a mock or live1 database. 102 | Be sure to modify the test case (or create your own) to point to your seed and migrations 103 | and include any additional steps to be run before tests in the `setUp()` method. 104 | 105 | 1 Note: If you are using database tests that require a live database connection 106 | you will need to rename **phpunit.xml.dist** to **phpunit.xml**, uncomment the database 107 | configuration lines and add your connection details. Prevent **phpunit.xml** from being 108 | tracked in your repo by adding it to **.gitignore**. 109 | -------------------------------------------------------------------------------- /tests/_support/Autoloader/UnnamespacedClass.php: -------------------------------------------------------------------------------- 1 | showError($oops); 29 | } 30 | } 31 | 32 | public function helpme() 33 | { 34 | $this->call('help'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/_support/Config/BadRegistrar.php: -------------------------------------------------------------------------------- 1 | [ 16 | 'first', 17 | 'second', 18 | ], 19 | 'format' => 'nice', 20 | 'fruit' => [ 21 | 'apple', 22 | 'banana', 23 | ], 24 | ]; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /tests/_support/Config/Routes.php: -------------------------------------------------------------------------------- 1 | add('testing', 'TestController::index'); 8 | -------------------------------------------------------------------------------- /tests/_support/Controllers/Popcorn.php: -------------------------------------------------------------------------------- 1 | respond('Oops', 567, 'Surprise'); 25 | } 26 | 27 | public function popper() 28 | { 29 | throw new \RuntimeException('Surprise', 500); 30 | } 31 | 32 | public function weasel() 33 | { 34 | $this->respond('', 200); 35 | } 36 | 37 | public function oops() 38 | { 39 | $this->failUnauthorized(); 40 | } 41 | 42 | public function goaway() 43 | { 44 | return redirect()->to('/'); 45 | } 46 | 47 | // @see https://github.com/codeigniter4/CodeIgniter4/issues/1834 48 | public function index3() 49 | { 50 | $response = $this->response->setJSON([ 51 | 'lang' => $this->request->getLocale(), 52 | ]); 53 | 54 | // echo var_dump($this->response->getBody()); 55 | return $response; 56 | } 57 | 58 | public function canyon() 59 | { 60 | echo 'Hello-o-o'; 61 | } 62 | 63 | public function cat() 64 | { 65 | } 66 | 67 | public function json() 68 | { 69 | $this->responsd(['answer' => 42]); 70 | } 71 | 72 | public function xml() 73 | { 74 | $this->respond('cat'); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /tests/_support/Database/Migrations/20160428212500_Create_test_tables.php: -------------------------------------------------------------------------------- 1 | db->DBDriver === 'SQLite3' ? 'unique' : 'auto_increment'; 9 | 10 | // User Table 11 | $this->forge->addField([ 12 | 'id' => [ 13 | 'type' => 'INTEGER', 14 | 'constraint' => 3, 15 | $unique_or_auto => true, 16 | ], 17 | 'name' => [ 18 | 'type' => 'VARCHAR', 19 | 'constraint' => 80, 20 | ], 21 | 'email' => [ 22 | 'type' => 'VARCHAR', 23 | 'constraint' => 100, 24 | ], 25 | 'country' => [ 26 | 'type' => 'VARCHAR', 27 | 'constraint' => 40, 28 | ], 29 | 'created_at' => [ 30 | 'type' => 'DATETIME', 31 | 'null' => true, 32 | ], 33 | 'updated_at' => [ 34 | 'type' => 'DATETIME', 35 | 'null' => true, 36 | ], 37 | 'deleted_at' => [ 38 | 'type' => 'DATETIME', 39 | 'null' => true, 40 | ], 41 | ]); 42 | $this->forge->addKey('id', true); 43 | $this->forge->createTable('user', true); 44 | 45 | // Job Table 46 | $this->forge->addField([ 47 | 'id' => [ 48 | 'type' => 'INTEGER', 49 | 'constraint' => 3, 50 | $unique_or_auto => true, 51 | ], 52 | 'name' => [ 53 | 'type' => 'VARCHAR', 54 | 'constraint' => 40, 55 | ], 56 | 'description' => [ 57 | 'type' => 'TEXT', 58 | 'null' => true, 59 | ], 60 | 'created_at' => [ 61 | 'type' => 'INTEGER', 62 | 'constraint' => 11, 63 | 'null' => true, 64 | ], 65 | 'updated_at' => [ 66 | 'type' => 'INTEGER', 67 | 'constraint' => 11, 68 | 'null' => true, 69 | ], 70 | 'deleted_at' => [ 71 | 'type' => 'INTEGER', 72 | 'constraint' => 11, 73 | 'null' => true, 74 | ], 75 | ]); 76 | $this->forge->addKey('id', true); 77 | $this->forge->createTable('job', true); 78 | 79 | // Misc Table 80 | $this->forge->addField([ 81 | 'id' => [ 82 | 'type' => 'INTEGER', 83 | 'constraint' => 3, 84 | $unique_or_auto => true, 85 | ], 86 | 'key' => [ 87 | 'type' => 'VARCHAR', 88 | 'constraint' => 40, 89 | ], 90 | 'value' => ['type' => 'TEXT'], 91 | ]); 92 | $this->forge->addKey('id', true); 93 | $this->forge->createTable('misc', true); 94 | 95 | // Empty Table 96 | $this->forge->addField([ 97 | 'id' => [ 98 | 'type' => 'INTEGER', 99 | 'constraint' => 3, 100 | $unique_or_auto => true, 101 | ], 102 | 'name' => [ 103 | 'type' => 'VARCHAR', 104 | 'constraint' => 40, 105 | ], 106 | 'created_at' => [ 107 | 'type' => 'DATE', 108 | 'null' => true, 109 | ], 110 | 'updated_at' => [ 111 | 'type' => 'DATE', 112 | 'null' => true, 113 | ], 114 | ]); 115 | $this->forge->addKey('id', true); 116 | $this->forge->createTable('empty', true); 117 | 118 | // Secondary Table 119 | $this->forge->addField([ 120 | 'id' => [ 121 | 'type' => 'INTEGER', 122 | 'constraint' => 3, 123 | $unique_or_auto => true, 124 | ], 125 | 'key' => [ 126 | 'type' => 'VARCHAR', 127 | 'constraint' => 40, 128 | ], 129 | 'value' => ['type' => 'TEXT'], 130 | ]); 131 | $this->forge->addKey('id', true); 132 | $this->forge->createTable('secondary', true); 133 | } 134 | 135 | //-------------------------------------------------------------------- 136 | 137 | public function down() 138 | { 139 | $this->forge->dropTable('user', true); 140 | $this->forge->dropTable('job', true); 141 | $this->forge->dropTable('misc', true); 142 | $this->forge->dropTable('empty', true); 143 | $this->forge->dropTable('secondary', true); 144 | } 145 | 146 | //-------------------------------------------------------------------- 147 | 148 | } 149 | -------------------------------------------------------------------------------- /tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php: -------------------------------------------------------------------------------- 1 | [ 13 | 'type' => 'varchar', 14 | 'constraint' => 31, 15 | ], 16 | 'uid' => [ 17 | 'type' => 'varchar', 18 | 'constraint' => 31, 19 | ], 20 | 'class' => [ 21 | 'type' => 'varchar', 22 | 'constraint' => 63, 23 | ], 24 | 'icon' => [ 25 | 'type' => 'varchar', 26 | 'constraint' => 31, 27 | ], 28 | 'summary' => [ 29 | 'type' => 'varchar', 30 | 'constraint' => 255, 31 | ], 32 | 'created_at' => [ 33 | 'type' => 'datetime', 34 | 'null' => true, 35 | ], 36 | 'updated_at' => [ 37 | 'type' => 'datetime', 38 | 'null' => true, 39 | ], 40 | 'deleted_at' => [ 41 | 'type' => 'datetime', 42 | 'null' => true, 43 | ], 44 | ]; 45 | 46 | $this->forge->addField('id'); 47 | $this->forge->addField($fields); 48 | 49 | $this->forge->addKey('name'); 50 | $this->forge->addKey('uid'); 51 | $this->forge->addKey(['deleted_at', 'id']); 52 | $this->forge->addKey('created_at'); 53 | 54 | $this->forge->createTable('factories'); 55 | } 56 | 57 | public function down() 58 | { 59 | $this->forge->dropTable('factories'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/_support/Database/Seeds/AnotherSeeder.php: -------------------------------------------------------------------------------- 1 | 'Jerome Lohan', 9 | 'email' => 'jlo@lohanenterprises.com', 10 | 'country' => 'UK', 11 | ]; 12 | 13 | $this->db->table('user')->insert($row); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/_support/Database/Seeds/CITestSeeder.php: -------------------------------------------------------------------------------- 1 | [ 10 | [ 11 | 'name' => 'Derek Jones', 12 | 'email' => 'derek@world.com', 13 | 'country' => 'US', 14 | ], 15 | [ 16 | 'name' => 'Ahmadinejad', 17 | 'email' => 'ahmadinejad@world.com', 18 | 'country' => 'Iran', 19 | ], 20 | [ 21 | 'name' => 'Richard A Causey', 22 | 'email' => 'richard@world.com', 23 | 'country' => 'US', 24 | ], 25 | [ 26 | 'name' => 'Chris Martin', 27 | 'email' => 'chris@world.com', 28 | 'country' => 'UK', 29 | ], 30 | ], 31 | 'job' => [ 32 | [ 33 | 'name' => 'Developer', 34 | 'description' => 'Awesome job, but sometimes makes you bored', 35 | ], 36 | [ 37 | 'name' => 'Politician', 38 | 'description' => 'This is not really a job', 39 | ], 40 | [ 41 | 'name' => 'Accountant', 42 | 'description' => 'Boring job, but you will get free snack at lunch', 43 | ], 44 | [ 45 | 'name' => 'Musician', 46 | 'description' => 'Only Coldplay can actually called Musician', 47 | ], 48 | ], 49 | 'misc' => [ 50 | [ 51 | 'key' => '\\xxxfoo456', 52 | 'value' => 'Entry with \\xxx', 53 | ], 54 | [ 55 | 'key' => '\\%foo456', 56 | 'value' => 'Entry with \\%', 57 | ], 58 | [ 59 | 'key' => 'spaces and tabs', 60 | 'value' => ' One two three tab', 61 | ], 62 | ], 63 | ]; 64 | 65 | foreach ($data as $table => $dummy_data) 66 | { 67 | $this->db->table($table)->truncate(); 68 | 69 | foreach ($dummy_data as $single_dummy_data) 70 | { 71 | $this->db->table($table)->insert($single_dummy_data); 72 | } 73 | } 74 | } 75 | 76 | //-------------------------------------------------------------------- 77 | 78 | } 79 | -------------------------------------------------------------------------------- /tests/_support/Database/Seeds/ExampleSeeder.php: -------------------------------------------------------------------------------- 1 | 'Test Factory', 12 | 'uid' => 'test001', 13 | 'class' => 'Factories\Tests\NewFactory', 14 | 'icon' => 'fas fa-puzzle-piece', 15 | 'summary' => 'Longer sample text for testing', 16 | ], 17 | [ 18 | 'name' => 'Widget Factory', 19 | 'uid' => 'widget', 20 | 'class' => 'Factories\Tests\WidgetPlant', 21 | 'icon' => 'fas fa-puzzle-piece', 22 | 'summary' => 'Create widgets in your factory', 23 | ], 24 | [ 25 | 'name' => 'Evil Factory', 26 | 'uid' => 'evil-maker', 27 | 'class' => 'Factories\Evil\MyFactory', 28 | 'icon' => 'fas fa-book-dead', 29 | 'summary' => 'Abandon all hope, ye who enter here', 30 | ], 31 | ]; 32 | 33 | $builder = $this->db->table('factories'); 34 | 35 | foreach ($factories as $factory) 36 | { 37 | $builder->insert($factory); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/_support/DatabaseTestCase.php: -------------------------------------------------------------------------------- 1 | load($file, $locale, $return); 15 | } 16 | 17 | //-------------------------------------------------------------------- 18 | 19 | /** 20 | * Expose the loaded language files 21 | */ 22 | public function loaded(string $locale = 'en') 23 | { 24 | return $this->loadedFiles[$locale]; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /tests/_support/Language/ab-CD/Allin.php: -------------------------------------------------------------------------------- 1 | 'Pyramid of Giza', 5 | 'tre' => 'Colossus of Rhodes', 6 | 'fiv' => 'Temple of Artemis', 7 | 'sev' => 'Hanging Gardens of Babylon', 8 | ]; 9 | -------------------------------------------------------------------------------- /tests/_support/Language/ab/Allin.php: -------------------------------------------------------------------------------- 1 | 'gluttony', 5 | 'tre' => 'greed', 6 | 'six' => 'envy', 7 | 'sev' => 'pride', 8 | ]; 9 | -------------------------------------------------------------------------------- /tests/_support/Language/en-ZZ/More.php: -------------------------------------------------------------------------------- 1 | 'These are not the droids you are looking for', 4 | 'notaMoon' => "It's made of cheese", 5 | 'wisdom' => 'There is no try', 6 | ]; 7 | -------------------------------------------------------------------------------- /tests/_support/Language/en/Allin.php: -------------------------------------------------------------------------------- 1 | 'four calling birds', 5 | 'fiv' => 'five golden rings', 6 | 'six' => 'six geese a laying', 7 | 'sev' => 'seven swans a swimming', 8 | ]; 9 | -------------------------------------------------------------------------------- /tests/_support/Language/en/Core.php: -------------------------------------------------------------------------------- 1 | '{0} extension could not be found.', 19 | 'bazillion' => 'billions and billions', // adds a new setting 20 | ]; 21 | -------------------------------------------------------------------------------- /tests/_support/Language/en/More.php: -------------------------------------------------------------------------------- 1 | 'These are not the droids you are looking for', 5 | 'notaMoon' => "That's no moon... it's a space station", 6 | 'cannotMove' => 'I have a very bad feeling about this', 7 | ]; 8 | -------------------------------------------------------------------------------- /tests/_support/Language/ru/Language.php: -------------------------------------------------------------------------------- 1 | 'Whatever this would be, translated', 5 | ]; 6 | -------------------------------------------------------------------------------- /tests/_support/Libraries/ConfigReader.php: -------------------------------------------------------------------------------- 1 | handles = $config['handles'] ?? []; 29 | $this->destination = $this->path . 'log-' . date('Y-m-d') . '.' . $this->fileExtension; 30 | 31 | self::$logs = []; 32 | } 33 | 34 | //-------------------------------------------------------------------- 35 | 36 | /** 37 | * Handles logging the message. 38 | * If the handler returns false, then execution of handlers 39 | * will stop. Any handlers that have not run, yet, will not 40 | * be run. 41 | * 42 | * @param $level 43 | * @param $message 44 | * 45 | * @return boolean 46 | */ 47 | public function handle($level, $message): bool 48 | { 49 | $date = date($this->dateFormat); 50 | 51 | self::$logs[] = strtoupper($level) . ' - ' . $date . ' --> ' . $message; 52 | 53 | return true; 54 | } 55 | 56 | //-------------------------------------------------------------------- 57 | 58 | public static function getLogs() 59 | { 60 | return self::$logs; 61 | } 62 | 63 | //-------------------------------------------------------------------- 64 | } 65 | -------------------------------------------------------------------------------- /tests/_support/MigrationTestMigrations/Database/Migrations/2018-01-24-102300_Another_migration.py: -------------------------------------------------------------------------------- 1 | forge->addField([ 8 | 'key' => [ 9 | 'type' => 'VARCHAR', 10 | 'constraint' => 255, 11 | ], 12 | ]); 13 | $this->forge->createTable('foo', true); 14 | 15 | $this->db->table('foo')->insert([ 16 | 'key' => 'foobar', 17 | ]); 18 | } 19 | 20 | public function down() 21 | { 22 | $this->forge->dropTable('foo', true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/_support/MigrationTestMigrations/Database/Migrations/2018-01-24-102301_Some_migration.php: -------------------------------------------------------------------------------- 1 | forge->addField([ 8 | 'key' => [ 9 | 'type' => 'VARCHAR', 10 | 'constraint' => 255, 11 | ], 12 | ]); 13 | $this->forge->createTable('foo', true); 14 | 15 | $this->db->table('foo')->insert([ 16 | 'key' => 'foobar', 17 | ]); 18 | } 19 | 20 | public function down() 21 | { 22 | $this->forge->dropTable('foo', true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/_support/MigrationTestMigrations/Database/Migrations/2018-01-24-102302_Another_migration.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'type' => 'VARCHAR', 10 | 'constraint' => 255, 11 | ], 12 | ]; 13 | $this->forge->addColumn('foo', $fields); 14 | 15 | $this->db->table('foo')->insert([ 16 | 'key' => 'foobar', 17 | 'value' => 'raboof', 18 | ]); 19 | } 20 | 21 | public function down() 22 | { 23 | if ($this->db->tableExists('foo')) 24 | { 25 | $this->forge->dropColumn('foo', 'value'); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/_support/Models/EntityModel.php: -------------------------------------------------------------------------------- 1 | tokens[] = 'beforeInsert'; 35 | 36 | return $data; 37 | } 38 | 39 | protected function afterInsertMethod(array $data) 40 | { 41 | $this->tokens[] = 'afterInsert'; 42 | 43 | return $data; 44 | } 45 | 46 | protected function beforeUpdateMethod(array $data) 47 | { 48 | $this->tokens[] = 'beforeUpdate'; 49 | 50 | return $data; 51 | } 52 | 53 | protected function afterUpdateMethod(array $data) 54 | { 55 | $this->tokens[] = 'afterUpdate'; 56 | 57 | return $data; 58 | } 59 | 60 | protected function afterFindMethod(array $data) 61 | { 62 | $this->tokens[] = 'afterFind'; 63 | 64 | return $data; 65 | } 66 | 67 | protected function afterDeleteMethod(array $data) 68 | { 69 | $this->tokens[] = 'afterDelete'; 70 | 71 | return $data; 72 | } 73 | 74 | public function hasToken(string $token) 75 | { 76 | return in_array($token, $this->tokens); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /tests/_support/Models/ExampleModel.php: -------------------------------------------------------------------------------- 1 | [ 22 | 'required', 23 | 'min_length[10]', 24 | 'errors' => [ 25 | 'min_length' => 'Minimum Length Error', 26 | ] 27 | ], 28 | 'token' => 'in_list[{id}]', 29 | ]; 30 | } 31 | -------------------------------------------------------------------------------- /tests/_support/Models/ValidModel.php: -------------------------------------------------------------------------------- 1 | [ 22 | 'required', 23 | 'min_length[3]', 24 | ], 25 | 'token' => 'permit_empty|in_list[{id}]', 26 | ]; 27 | 28 | protected $validationMessages = [ 29 | 'name' => [ 30 | 'required' => 'You forgot to name the baby.', 31 | 'min_length' => 'Too short, man!', 32 | ], 33 | ]; 34 | } 35 | -------------------------------------------------------------------------------- /tests/_support/RESTful/Worker.php: -------------------------------------------------------------------------------- 1 | mockSession(); 19 | } 20 | 21 | /** 22 | * Pre-loads the mock session driver into $this->session. 23 | * 24 | * @var string 25 | */ 26 | protected function mockSession() 27 | { 28 | $config = config('App'); 29 | $this->session = new MockSession(new ArrayHandler($config, '0.0.0.0'), $config); 30 | \Config\Services::injectMock('session', $this->session); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/_support/SomeEntity.php: -------------------------------------------------------------------------------- 1 | null, 11 | 'bar' => null, 12 | ]; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /tests/_support/Validation/TestRules.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/_support/View/Views/simpler.php: -------------------------------------------------------------------------------- 1 |

    {testString}

    -------------------------------------------------------------------------------- /tests/_support/coverage.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Code Coverage Report: 4 | 2016-03-31 06:36:22 5 | 6 | Summary: 7 | Classes: 29.51% (18/61) 8 | Methods: 42.91% (227/529) 9 | Lines: 53.58% (1967/3671) 10 | 11 | \CodeIgniter::CodeIgniter 12 | Methods: 28.57% ( 4/14) Lines: 69.11% ( 85/123) 13 | \CodeIgniter::Controller 14 | Methods: 0.00% ( 0/ 2) Lines: 66.67% ( 6/ 9) 15 | \CodeIgniter\Autoloader::Autoloader 16 | Methods: 42.86% ( 3/ 7) Lines: 89.36% ( 42/ 47) 17 | \CodeIgniter\Autoloader::FileLocator 18 | Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 39/ 39) 19 | \CodeIgniter\CLI::CLI 20 | Methods: 6.25% ( 1/16) Lines: 2.54% ( 3/118) 21 | \CodeIgniter\Config::AutoloadConfig 22 | Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 52/ 52) 23 | \CodeIgniter\Config::BaseConfig 24 | Methods: 50.00% ( 1/ 2) Lines: 83.33% ( 15/ 18) 25 | \CodeIgniter\Config::DotEnv 26 | Methods: 62.50% ( 5/ 8) Lines: 89.29% ( 50/ 56) 27 | \CodeIgniter\Database::BaseBuilder 28 | Methods: 43.33% (39/90) Lines: 62.25% (460/739) 29 | \CodeIgniter\Database::BaseConnection 30 | Methods: 0.00% ( 0/17) Lines: 3.33% ( 2/ 60) 31 | \CodeIgniter\Database::BaseQuery 32 | Methods: 64.71% (11/17) Lines: 74.44% ( 67/ 90) 33 | \CodeIgniter\Debug::Exceptions 34 | Methods: 10.00% ( 1/10) Lines: 2.91% ( 3/103) 35 | \CodeIgniter\Debug::Timer 36 | Methods: 75.00% ( 3/ 4) Lines: 95.24% ( 20/ 21) 37 | \CodeIgniter\HTTP::CLIRequest 38 | Methods: 33.33% ( 2/ 6) Lines: 40.00% ( 14/ 35) 39 | \CodeIgniter\HTTP::CURLRequest 40 | Methods: 62.50% (10/16) Lines: 68.49% (100/146) 41 | \CodeIgniter\HTTP::Header 42 | Methods: 88.89% ( 8/ 9) Lines: 96.88% ( 31/ 32) 43 | \CodeIgniter\HTTP::IncomingRequest 44 | Methods: 60.00% ( 6/10) Lines: 54.05% ( 40/ 74) 45 | \CodeIgniter\HTTP::Message 46 | Methods: 78.57% (11/14) Lines: 86.21% ( 50/ 58) 47 | \CodeIgniter\HTTP::Negotiate 48 | Methods: 75.00% ( 9/12) Lines: 87.65% ( 71/ 81) 49 | \CodeIgniter\HTTP::Request 50 | Methods: 57.14% ( 4/ 7) Lines: 45.79% ( 49/107) 51 | \CodeIgniter\HTTP::Response 52 | Methods: 53.85% ( 7/13) Lines: 79.01% ( 64/ 81) 53 | \CodeIgniter\HTTP::URI 54 | Methods: 81.82% (27/33) Lines: 93.44% (171/183) 55 | \CodeIgniter\HTTP\Files::FileCollection 56 | Methods: 66.67% ( 4/ 6) Lines: 96.49% ( 55/ 57) 57 | \CodeIgniter\HTTP\Files::UploadedFile 58 | Methods: 42.86% ( 6/14) Lines: 39.22% ( 20/ 51) 59 | \CodeIgniter\Hooks::Hooks 60 | Methods: 66.67% ( 4/ 6) Lines: 92.31% ( 36/ 39) 61 | \CodeIgniter\Log::Logger 62 | Methods: 76.92% (10/13) Lines: 92.05% ( 81/ 88) 63 | \CodeIgniter\Router::RouteCollection 64 | Methods: 74.36% (29/39) Lines: 79.64% (133/167) 65 | \CodeIgniter\Router::Router 66 | Methods: 37.50% ( 6/16) Lines: 78.57% ( 77/ 98) 67 | \CodeIgniter\Security::Security 68 | Methods: 100.00% ( 6/ 6) Lines: 100.00% ( 50/ 50) 69 | \CodeIgniter\View::View 70 | Methods: 85.71% ( 6/ 7) Lines: 97.14% ( 34/ 35) 71 | -------------------------------------------------------------------------------- /tests/database/ExampleDatabaseTest.php: -------------------------------------------------------------------------------- 1 | findAll(); 20 | 21 | // Make sure the count is as expected 22 | $this->assertCount(3, $objects); 23 | } 24 | 25 | public function testSoftDeleteLeavesRow() 26 | { 27 | $model = new ExampleModel(); 28 | $this->setPrivateProperty($model, 'useSoftDeletes', true); 29 | 30 | $object = $model->first(); 31 | $model->delete($object->id); 32 | 33 | // The model should no longer find it 34 | $this->assertNull($model->find($object->id)); 35 | 36 | // ... but it should still be in the database 37 | $result = $model->builder()->where('id', $object->id)->get()->getResult(); 38 | 39 | $this->assertCount(1, $result); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/session/ExampleSessionTest.php: -------------------------------------------------------------------------------- 1 | session->set('logged_in', 123); 13 | 14 | $value = $this->session->get('logged_in'); 15 | 16 | $this->assertEquals(123, $value); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/unit/HealthTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($test); 15 | } 16 | 17 | public function testBaseUrlHasBeenSet() 18 | { 19 | $env = $config = false; 20 | 21 | // First check in .env 22 | if (is_file(HOMEPATH . '.env')) 23 | { 24 | $env = (bool) preg_grep("/^app\.baseURL = './", file(HOMEPATH . '.env')); 25 | } 26 | 27 | // Then check the actual config file 28 | $reader = new \Tests\Support\Libraries\ConfigReader(); 29 | $config = ! empty($reader->baseUrl); 30 | 31 | $this->assertTrue($env || $config); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /writable/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Deny from all 6 | 7 | -------------------------------------------------------------------------------- /writable/cache/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

    Directory access is forbidden.

    9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/logs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

    Directory access is forbidden.

    9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/session/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

    Directory access is forbidden.

    9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/uploads/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

    Directory access is forbidden.

    9 | 10 | 11 | 12 | --------------------------------------------------------------------------------