Giter Site home page Giter Site logo

vphantom / pyritephp Goto Github PK

View Code? Open in Web Editor NEW
3.0 4.0 0.0 187 KB

PHP/Bootstrap framework to kick-start multilingual web application development

License: MIT License

PHP 88.16% CSS 2.94% JavaScript 8.60% Makefile 0.30%
php bootstrap-framework twig-templates php-composer

pyritephp's Introduction

PyritePHP

license GitHub release

PHP 5 and Bootstrap 3 framework to kick-start multilingual web application development

Simple event-driven framework for creating PHP 5 applications backed by a PDO database and with a Twitter Bootstrap user interface. Emphasis has been given on security:

  • SQL queries use placeholders, of course, and a whitelist for column names;
  • User passwords are saved in cryptographically secure hash form in the database;
  • Twig templating has escaping enabled globally by default;
  • Sessions are tied to the browser's IP address and fingerprint to reduce the risk of hijacking;
  • Form displays are tied to the current session to elimiate duplicate submissions and further reduce the risks associated with session hijacking and scripted attacks;
  • New users require e-mail confirmation to become active;
  • E-mail and password changes require password re-entry and trigger e-mail notifications;
  • Registration and password reset processes don't leak whether an e-mail is already signed up;
  • Covering 98% of users, forms are validated client-side to improve responsiveness.

Just use this repo as your starting point, modify this file and the contents of modules/ and templates/ to suit your needs. The rest of the developer documentation can be found in Developers.

Why the name "Pyrite"?

This framework was actually built as the starting point for a commercial project named "PyriteView" as a bilingual play on the words "Peer Review". The framework was then forked on its own as it is highly generic. The name "PyritePHP" then made sense, considering its origin.

Usage

Manually from scratch

$ composer require vphantom/pyritephp

Then in your main PHP file:

<?php

// Load dependencies provided by Composer
require_once __DIR__ . '/vendor/autoload.php';

// Bootstrap Pyrite
Pyrite::bootstrap(__DIR__);

// Route request
Pyrite::run();

// Shut down
Pyrite::shutdown();

The above program will only load up and fire a single event if one is specified from the CLI. Our example application's installation is launched with, for example:

$ php ./index.php --trigger install

Automatically from our example application

You probably want to use our example basic application as a full-featured starting point instead, for example if you want to create foo/:

$ composer create-project vphantom/pyritephp-example foo

Requirements

  • PHP 5.5 or later
  • PHP extension modules: mbstring, mcrypt, pdo_sqlite, readline
  • SQLite 3
  • Typical Linux command line tools: make, wget, gzip
  • A web server of course

Web Server Configuration

In order to produce clean, technology-agnostic URLs such as http://www.yourdomain.com/articles/127, you need to tell your web server to internally redirect requests for non-existent files to /index.php, which will look in PATH_INFO for details. We also want to prevent access to private files.

Here are sample configurations for major server software:

Apache

RewriteEngine on

RewriteRule ^(bin|lib|modules|node_modules|templates|var|vendor) - [F,L,NC]

RewriteRule ^$ /index.php [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+) /index.php/$1 [L]

Nginx

location ~ /(bin|lib|modules|node_modules|templates|var|vendor) {
    deny all;
    return 404;
}

location ~ \.php$ {
	# Usual FastCGI configuration
}

location / {
    index index.html index.htm index.php;
    try_files $uri $uri/ $uri/index.php /index.php;
}

Lighttpd

# TODO: Deny private directories
url.rewrite-if-not-file (
    "^(.*)$" => "/index.php/$1"
    "^/(.*)$" => "/index.php/$1"
)

Configuration

If you used our example application, edit config.ini to change any defaults as needed and run make init. This will automatically download and set up the latest version of PHP's Composer package manager in the current directory, then use it to download runtime dependencies locally. Finally, it will create the database tables and the administrative user so you can log into your new installation. You will be prompted on the command line for an e-mail address and password to use for that unrestricted account. (NOTE: This prompt requires PHP's readline, so it will not work on Windows.)

You will also need to make sure that your web server or PHP process has read-write access to the var/ directory where the database and various other files are stored. This is not done by the Makefile because it requires root access and knowledge of which group your web server is a part of (often www-data, but not always):

mkdir var
chgrp www-data var
chmod 6770 var
cd var
mkdir sessions twig_cache
chmod 6770 sessions twig_cache

Crontab

Trigger daily and hourly events with the same user as your web server:

7	4	*	*	*	/usr/bin/php /web/your_site/index.php --trigger daily
11	*	*	*	*	/usr/bin/php /web/your_site/index.php --trigger hourly

Updating

While the example skeleton isn't upgradeable since it consisted of a simple starting point for your own application, everything else is one composer update away, conveniently available in make update if you used the example application.

Acknowledgements

This application would not have been possible within a reasonable time frame without the help of the following:

Server-side

  • The PHP language
  • The SQLite database engine
  • The Sphido Events library to facilitate event-driven design
  • The Twig PHP templating library
  • The 100% PHP Gettext implementation

Client-side

Frameworks

  • jQuery 2 (I've had performance issues with version 3)
  • Twitter Bootstrap 3, including its gracious Glyphicon license

Utilities

  • ParsleyJS to validate forms client-side
  • Selectize to create rich, interactive form inputs
  • Timeago to display human-readable timestamp descriptions

Build Tools

  • Browserify
  • Clean-CSS
  • Uglify-JS

MIT License

Copyright (c) 2016-2020 Stephane Lavergne https://github.com/vphantom

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pyritephp's People

Contributors

dependabot[bot] avatar vphantom avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pyritephp's Issues

Delegate UI to downstream projects

All of assets/ should be moved downstream to PyritePHP-Example and PyriteView. This might involve some cleaning up in src/globals.php as well.

I have a second project which could benefit from PyritePHP, but it'll be using PureCSS or SemanticUI, not Bootstrap, so PyritePHP should provide the CGI service, sure, but not a sample functional GUI.

Allow sysadmin to log in as any user

We need a safe way for administrators to spoof logins as any other user for test purposes. A backdoor which is normally disabled doesn't sound quite safe enough, because it could be forgotten in an active state.

  • In config.ini, create global.admin_backdoor_date and global.admin_backdoor_password.

  • In Pyrite\User::login(), before invoking password_verify() on a valid user, check if today is the backdoor date and password matches the backdoor password first.

Log watchdog bug reports in addition to e-mail

In some broken e-mail setups, log reports do not reach their destination. Let's offer users of Watchdog.php the option of saving to a log file in addition to (or instead of) e-mailing.

Create test suite

I usually develop in [documentation, test, code] cycles, but time ran short for PyriteView. Let's start with an analogy with what I do on the Node side:

  • "make test" runs Istanbul which is a code coverage reporter. It runs all my test scripts in find-like fashion and generates an HTML tree of pretty reports and some data files.

  • Each test script depends on Tape for producing TAP output.

  • For CLI usage, I pass TAP through Faucet to make it pretty.

  • For Travis-CI, I don't. Travis-CI is also configured to invoke Coveralls to send Coveralls.IO a copy of Istanbul's "lcov.info".

In PHP, PHPUnit is probably the closest, although not nearly as simple as Perl's Test::More and Node's Tape. I'm tempted to do like TestTAP and update my old Test.inc to offer a Test::More/Tape style API wrapped in php-code-coverage.

  • Install Linux distribution package php7.0-xdebug. This probably means composer.json adds its first dev requirement, for "xdebug ~2.5".

  • Install PHPUnit stable: composer require --dev phpunit/phpunit ^6.0

  • Create at least one test to confirm that reporting works, fine-tune Makefile for options I prefer.

  • Install PHP-Coveralls: composer require --dev satooshi/php-coveralls to convert/send PHPUnit's coverage report (which is in "Clover" format?) to Coveralls.IO.

  • Set up repo with Travis-CI:

language: php

php:
 - 5.6
 - 7.0

before_script:
 - wget http://getcomposer.org/composer.phar
 - php composer.phar install --dev --no-interaction

script:
 - mkdir -p build/logs
 - phpunit --coverage-clover build/logs/clover.xml

after_script:
 - [php?] vendor/bin/coveralls -v

Bypass NONCE on specific forms

All forms use NONCE validation. We need to create a means for some forms to ignore NONCE if some other condition is met. Perhaps #12 could set an ephemeral variable in the session, which says "bypass NONCE for the very next form". NONCE validation would notice this variable, delete it, and succeed.

MSIE doesn't have Number.isInteger()

We need to polyfill with:

Number.isInteger = Number.isInteger || function(value) {
  return typeof value === "number" &&
    isFinite(value) &&
    Math.floor(value) === value;
};

Deep link logins

Tag along a redirect URL to login links, somehow hashed to prevent tampering along the way.

Make usernames case-insensitive

Significant omission in v1.0: users.email should be stored in lowercase and lookups should also be made lowercase at all times.

Clean up event vs OO API

This will break PyritePHP-Example and PyriteView, so it is pushed back to the next major release. Right now our API is a majority of events and a minority of OO. With events, we solved problems of caller not knowing the handler, of prioritizing multiple handlers for a single trigger and of cascading handlers as content filters.

Because of these, I guess event-driven wins over OO. We need to clean up accordingly and create more robust structure and documentation for those. I'd hope we can do better than Class::bootstrap().

Use global composer if available

  • The Makefile should set $(COMPOSER) to which composer if it is available and only resort to installing bin/composer if it is not found.

  • In the update section, skip self-update if composer isn't bin/composer.

Outbox edits are lost when sending

If we add text in an outgoing e-mail, it will not be saved to the DB, and consequently the send operation that follows will send the unedited version.

PHP's explode() creates elements out of thin air

It's a known bug with PHP, which like many other such things is a "won't fix" on their side: explode("") does not return array() but actually array("") that is, an array with one element.

Therefore, we need to refactor all uses of explode() to produce an empty array when given an empty string. The easiest way should probably be to create a global function that wraps around it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.