From d194c534af2a2009bbbd1120ce291dfa1f1bc12a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20Barn=C3=A5?=
Date: Fri, 6 Apr 2018 22:46:12 +0200
Subject: [PATCH] First commit
---
.phpcs.xml | 28 +
.phpdoc.xml | 14 +
.phpmd.xml | 43 +
.phpunit.xml | 22 +
Makefile | 444 +++++++++
cache/cimage/.gitignore | 4 +
composer.json | 22 +
config/di.php | 113 +++
config/error_reporting.php | 34 +
config/route.php | 37 +
config/route/404.php | 14 +
config/route/debug.php | 20 +
config/route/flat-file-content.php | 14 +
config/route/internal.php | 29 +
config/session.php | 12 +
config/url.php | 14 +
config/view.php | 24 +
content/debug.md | 7 +
content/index.md | 21 +
content/lek.md | 13 +
content/om.md | 16 +
content/redovisning.md | 53 ++
htdocs/.htaccess | 28 +
htdocs/.htaccess_anax | 14 +
htdocs/.htaccess_wwwstudent | 28 +
htdocs/cimage/img.php | 1197 ++++++++++++++++++++++++
htdocs/cimage/img_config.php | 7 +
htdocs/css/style.css | 113 +++
htdocs/demo/demo.php | 4 +
htdocs/favicon.ico | Bin 0 -> 32988 bytes
htdocs/img/blad.jpg | Bin 0 -> 3143 bytes
htdocs/img/car.png | Bin 0 -> 250786 bytes
htdocs/img/me.jpg | Bin 0 -> 52962 bytes
htdocs/index.php | 31 +
htdocs/js/main.js | 8 +
src/Page/DebugController.php | 44 +
src/Page/ErrorController.php | 87 ++
src/Page/FlatFileContentController.php | 57 ++
src/Page/Page.php | 51 +
src/route/app.php | 32 +
view/content/oophp/default.php | 18 +
view/debug/oophp/info.php | 45 +
view/debug/oophp/view.php | 23 +
view/footer/oophp/default.php | 15 +
view/header/oophp/default.php | 16 +
view/http_status/403.php | 20 +
view/http_status/404.php | 20 +
view/http_status/500.php | 20 +
view/http_status/default.php | 20 +
view/layout/oophp/default.php | 87 ++
view/navbar/oophp/default.php | 22 +
51 files changed, 3005 insertions(+)
create mode 100644 .phpcs.xml
create mode 100644 .phpdoc.xml
create mode 100644 .phpmd.xml
create mode 100644 .phpunit.xml
create mode 100644 Makefile
create mode 100644 cache/cimage/.gitignore
create mode 100644 composer.json
create mode 100644 config/di.php
create mode 100644 config/error_reporting.php
create mode 100644 config/route.php
create mode 100644 config/route/404.php
create mode 100644 config/route/debug.php
create mode 100644 config/route/flat-file-content.php
create mode 100644 config/route/internal.php
create mode 100644 config/session.php
create mode 100644 config/url.php
create mode 100644 config/view.php
create mode 100644 content/debug.md
create mode 100644 content/index.md
create mode 100644 content/lek.md
create mode 100644 content/om.md
create mode 100644 content/redovisning.md
create mode 100644 htdocs/.htaccess
create mode 100644 htdocs/.htaccess_anax
create mode 100644 htdocs/.htaccess_wwwstudent
create mode 100644 htdocs/cimage/img.php
create mode 100644 htdocs/cimage/img_config.php
create mode 100644 htdocs/css/style.css
create mode 100644 htdocs/demo/demo.php
create mode 100644 htdocs/favicon.ico
create mode 100644 htdocs/img/blad.jpg
create mode 100644 htdocs/img/car.png
create mode 100644 htdocs/img/me.jpg
create mode 100644 htdocs/index.php
create mode 100644 htdocs/js/main.js
create mode 100644 src/Page/DebugController.php
create mode 100644 src/Page/ErrorController.php
create mode 100644 src/Page/FlatFileContentController.php
create mode 100644 src/Page/Page.php
create mode 100644 src/route/app.php
create mode 100644 view/content/oophp/default.php
create mode 100644 view/debug/oophp/info.php
create mode 100644 view/debug/oophp/view.php
create mode 100644 view/footer/oophp/default.php
create mode 100644 view/header/oophp/default.php
create mode 100644 view/http_status/403.php
create mode 100644 view/http_status/404.php
create mode 100644 view/http_status/500.php
create mode 100644 view/http_status/default.php
create mode 100644 view/layout/oophp/default.php
create mode 100644 view/navbar/oophp/default.php
diff --git a/.phpcs.xml b/.phpcs.xml
new file mode 100644
index 0000000..4f56c6c
--- /dev/null
+++ b/.phpcs.xml
@@ -0,0 +1,28 @@
+
+
+ Custom rule set.
+
+ .
+
+ doc/
+ htdocs/
+ view/
+ vendor/
+
+
+
+
+
+
+
+
+
diff --git a/.phpdoc.xml b/.phpdoc.xml
new file mode 100644
index 0000000..8212098
--- /dev/null
+++ b/.phpdoc.xml
@@ -0,0 +1,14 @@
+
+
+ Anax API Documentation
+
+ doc/api
+
+
+ doc/api
+
+
+ src
+ vendor/anax/*/src
+
+
diff --git a/.phpmd.xml b/.phpmd.xml
new file mode 100644
index 0000000..5a5b649
--- /dev/null
+++ b/.phpmd.xml
@@ -0,0 +1,43 @@
+
+
+
+ Custom rule set for oophp course.
+
+
+ doc/
+ htdocs/
+ view/
+ vendor/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.phpunit.xml b/.phpunit.xml
new file mode 100644
index 0000000..520de75
--- /dev/null
+++ b/.phpunit.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ test
+
+
+
+
+
+ src
+
+
+
+
+
+
+
+
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cdb5039
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,444 @@
+#!/usr/bin/env make
+#
+# An Anax module.
+# See organisation on GitHub: https://github.com/canax
+
+# ------------------------------------------------------------------------
+#
+# General stuff, reusable for all Makefiles.
+#
+
+# Detect OS
+OS = $(shell uname -s)
+
+# Defaults
+ECHO = echo
+
+# Make adjustments based on OS
+ifneq (, $(findstring CYGWIN, $(OS)))
+ ECHO = /bin/echo -e
+endif
+
+# Colors and helptext
+NO_COLOR = \033[0m
+ACTION = \033[32;01m
+OK_COLOR = \033[32;01m
+ERROR_COLOR = \033[31;01m
+WARN_COLOR = \033[33;01m
+
+# Print out colored action message
+ACTION_MESSAGE = $(ECHO) "$(ACTION)---> $(1)$(NO_COLOR)"
+
+# Which makefile am I in?
+WHERE-AM-I = $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
+THIS_MAKEFILE := $(call WHERE-AM-I)
+
+# Echo some nice helptext based on the target comment
+HELPTEXT = $(call ACTION_MESSAGE, $(shell egrep "^\# target: $(1) " $(THIS_MAKEFILE) | sed "s/\# target: $(1)[ ]*-[ ]* / /g"))
+
+# Check version and path to command and display on one line
+CHECK_VERSION = printf "%-15s %-10s %s\n" "`basename $(1)`" "`$(1) --version $(2)`" "`which $(1)`"
+
+# Get current working directory, it may not exist as environment variable.
+PWD = $(shell pwd)
+
+# target: help - Displays help.
+.PHONY: help
+help:
+ @$(call HELPTEXT,$@)
+ @sed '/^$$/q' $(THIS_MAKEFILE) | tail +3 | sed 's/#\s*//g'
+ @$(ECHO) "Usage:"
+ @$(ECHO) " make [target] ..."
+ @$(ECHO) "target:"
+ @egrep "^# target:" $(THIS_MAKEFILE) | sed 's/# target: / /g'
+
+
+
+# ------------------------------------------------------------------------
+#
+# Specifics for this project.
+#
+# Default values for arguments
+container ?= latest
+
+BIN := .bin
+PHPUNIT := $(BIN)/phpunit
+PHPLOC := $(BIN)/phploc
+PHPCS := $(BIN)/phpcs
+PHPCBF := $(BIN)/phpcbf
+PHPMD := $(BIN)/phpmd
+PHPDOC := $(BIN)/phpdoc
+BEHAT := $(BIN)/behat
+SHELLCHECK := $(BIN)/shellcheck
+BATS := $(BIN)/bats
+
+
+
+# target: prepare - Prepare for tests and build
+.PHONY: prepare
+prepare:
+ @$(call HELPTEXT,$@)
+ [ -d .bin ] || mkdir .bin
+ [ -d build ] || mkdir build
+ rm -rf build/*
+
+
+
+# target: clean - Removes generated files and directories.
+.PHONY: clean
+clean:
+ @$(call HELPTEXT,$@)
+ rm -rf build
+
+
+
+# target: clean-cache - Clean the cache.
+.PHONY: clean-cache
+clean-cache:
+ @$(call HELPTEXT,$@)
+ rm -rf cache/*/*
+
+
+
+# target: clean-all - Removes generated files and directories.
+.PHONY: clean-all
+clean-all: clean clean-cache
+ @$(call HELPTEXT,$@)
+ rm -rf .bin vendor composer.lock
+
+
+
+# target: check - Check version of installed tools.
+.PHONY: check
+check: check-tools-bash check-tools-php check-docker
+ @$(call HELPTEXT,$@)
+
+
+
+# target: test - Run all tests.
+.PHONY: test
+test: phpunit phpcs phpmd phploc behat shellcheck bats
+ @$(call HELPTEXT,$@)
+ composer validate
+
+
+
+# target: doc - Generate documentation.
+.PHONY: doc
+doc: phpdoc
+ @$(call HELPTEXT,$@)
+
+
+
+# target: build - Do all build
+.PHONY: build
+build: test doc #theme less-compile less-minify js-minify
+ @$(call HELPTEXT,$@)
+
+
+
+# target: install - Install all tools
+.PHONY: install
+install: prepare install-tools-php install-tools-bash
+ @$(call HELPTEXT,$@)
+
+
+
+# target: update - Update the codebase and tools.
+.PHONY: update
+update:
+ @$(call HELPTEXT,$@)
+ [ ! -d .git ] || git pull
+ composer update
+
+
+
+# target: tag-prepare - Prepare to tag new version.
+.PHONY: tag-prepare
+tag-prepare:
+ @$(call HELPTEXT,$@)
+
+
+
+# ----------------------------------------------------------------------------
+#
+# docker
+#
+# target: docker-up - Start all docker container="", or specific, default "latest".
+.PHONY: docker-up
+docker-up:
+ @$(call HELPTEXT,$@)
+ [ ! -f docker-compose.yaml ] || docker-compose -f docker-compose.yaml up -d $(container)
+
+
+
+# target: docker-stop - Stop running docker containers.
+.PHONY: docker-stop
+docker-stop:
+ @$(call HELPTEXT,$@)
+ [ ! -f docker-compose.yaml ] || docker-compose -f docker-compose.yaml stop
+
+
+
+# target: docker-run - Run container="" with what="" one off command.
+.PHONY: docker-run
+docker-run:
+ @$(call HELPTEXT,$@)
+ [ ! -f docker-compose.yaml ] || docker-compose -f docker-compose.yaml run $(container) $(what)
+
+
+
+# target: docker-bash - Run container="" with what="bash" one off command.
+.PHONY: docker-bash
+docker-bash:
+ @$(call HELPTEXT,$@)
+ [ ! -f docker-compose.yaml ] || docker-compose -f docker-compose.yaml run $(container) bash
+
+
+
+# target: docker-exec - Run container="" with what="" command in running container.
+.PHONY: docker-exec
+docker-exec:
+ @$(call HELPTEXT,$@)
+ [ ! -f docker-compose.yaml ] || docker-compose -f docker-compose.yaml exec $(container) $(what)
+
+
+
+# target: docker-install - Run make install in container="".
+.PHONY: docker-install
+docker-install:
+ @$(call HELPTEXT,$@)
+ [ ! -f docker-compose.yaml ] || docker-compose -f docker-compose.yaml run $(container) make install
+
+
+
+# target: docker-test - Run make test in container="".
+.PHONY: docker-test
+docker-test:
+ @$(call HELPTEXT,$@)
+ [ ! -f docker-compose.yaml ] || docker-compose -f docker-compose.yaml run $(container) make test
+
+
+
+# target: check-docker - Check versions of docker.
+.PHONY: check-docker
+check-docker:
+ @$(call HELPTEXT,$@)
+ @$(call CHECK_VERSION, docker, | cut -d" " -f3-)
+ @$(call CHECK_VERSION, docker-compose, | cut -d" " -f3-)
+
+
+
+# ------------------------------------------------------------------------
+#
+# PHP
+#
+
+# target: install-tools-php - Install PHP development tools.
+.PHONY: install-tools-php
+install-tools-php:
+ @$(call HELPTEXT,$@)
+ #curl -Lso $(PHPDOC) https://www.phpdoc.org/phpDocumentor.phar && chmod 755 $(PHPDOC)
+ curl -Lso $(PHPDOC) https://github.com/phpDocumentor/phpDocumentor2/releases/download/v2.9.0/phpDocumentor.phar && chmod 755 $(PHPDOC)
+
+ curl -Lso $(PHPCS) https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar && chmod 755 $(PHPCS)
+
+ curl -Lso $(PHPCBF) https://squizlabs.github.io/PHP_CodeSniffer/phpcbf.phar && chmod 755 $(PHPCBF)
+
+ curl -Lso $(PHPMD) http://static.phpmd.org/php/latest/phpmd.phar && chmod 755 $(PHPMD)
+
+ curl -Lso $(PHPLOC) https://phar.phpunit.de/phploc.phar && chmod 755 $(PHPLOC)
+
+ curl -Lso $(BEHAT) https://github.com/Behat/Behat/releases/download/v3.3.0/behat.phar && chmod 755 $(BEHAT)
+
+ # Get PHPUNIT depending on current PHP installation
+ curl -Lso $(PHPUNIT) https://phar.phpunit.de/phpunit-$(shell \
+ php -r "echo version_compare(PHP_VERSION, '7.0', '<') \
+ ? '5' \
+ : (version_compare(PHP_VERSION, '7.1', '>=') \
+ ? '7' \
+ : '6'\
+ );" \
+ ).phar && chmod 755 $(PHPUNIT)
+
+ [ ! -f composer.json ] || composer install
+
+
+
+# target: check-tools-php - Check versions of PHP tools.
+.PHONY: check-tools-php
+check-tools-php:
+ @$(call HELPTEXT,$@)
+ php --version && echo
+ composer show && echo
+ @$(call CHECK_VERSION, $(PHPUNIT))
+ @$(call CHECK_VERSION, $(PHPLOC))
+ @$(call CHECK_VERSION, $(PHPCS))
+ @$(call CHECK_VERSION, $(PHPMD))
+ @$(call CHECK_VERSION, $(PHPCBF))
+ @$(call CHECK_VERSION, $(PHPDOC))
+ @$(call CHECK_VERSION, $(BEHAT))
+
+
+
+# target: phpunit - Run unit tests for PHP.
+.PHONY: phpunit
+phpunit: prepare
+ @$(call HELPTEXT,$@)
+ [ ! -d "test" ] || $(PHPUNIT) --configuration .phpunit.xml
+
+
+
+# target: phpcs - Codestyle for PHP.
+.PHONY: phpcs
+phpcs: prepare
+ @$(call HELPTEXT,$@)
+ [ ! -f .phpcs.xml ] || $(PHPCS) --standard=.phpcs.xml | tee build/phpcs
+
+
+
+# target: phpcbf - Fix codestyle for PHP.
+.PHONY: phpcbf
+phpcbf:
+ @$(call HELPTEXT,$@)
+ifneq ($(wildcard test),)
+ [ ! -f .phpcs.xml ] || $(PHPCBF) --standard=.phpcs.xml
+else
+ [ ! -f .phpcs.xml ] || $(PHPCBF) --standard=.phpcs.xml src
+endif
+
+
+
+# target: phpmd - Mess detector for PHP.
+.PHONY: phpmd
+phpmd: prepare
+ @$(call HELPTEXT,$@)
+ - [ ! -f .phpmd.xml ] || $(PHPMD) . text .phpmd.xml | tee build/phpmd
+
+
+
+# target: phploc - Code statistics for PHP.
+.PHONY: phploc
+phploc: prepare
+ @$(call HELPTEXT,$@)
+ $(PHPLOC) src > build/phploc
+
+
+
+# target: phpdoc - Create documentation for PHP.
+.PHONY: phpdoc
+phpdoc:
+ @$(call HELPTEXT,$@)
+ [ ! -d doc ] || $(PHPDOC) --config=.phpdoc.xml
+
+
+
+# target: behat - Run behat for feature tests.
+.PHONY: behat
+behat:
+ @$(call HELPTEXT,$@)
+ [ ! -d features ] || $(BEHAT)
+
+
+# ------------------------------------------------------------------------
+#
+# Bash
+#
+
+# target: install-tools-bash - Install Bash development tools.
+.PHONY: install-tools-bash
+install-tools-bash:
+ @$(call HELPTEXT,$@)
+ # Shellcheck
+ curl -s https://storage.googleapis.com/shellcheck/shellcheck-latest.linux.x86_64.tar.xz | tar -xJ -C build/ && rm -f .bin/shellcheck && ln build/shellcheck-latest/shellcheck .bin/
+
+ # Bats
+ curl -Lso $(BIN)/bats-exec-suite https://raw.githubusercontent.com/sstephenson/bats/master/libexec/bats-exec-suite
+ curl -Lso $(BIN)/bats-exec-test https://raw.githubusercontent.com/sstephenson/bats/master/libexec/bats-exec-test
+ curl -Lso $(BIN)/bats-format-tap-stream https://raw.githubusercontent.com/sstephenson/bats/master/libexec/bats-format-tap-stream
+ curl -Lso $(BIN)/bats-preprocess https://raw.githubusercontent.com/sstephenson/bats/master/libexec/bats-preprocess
+ curl -Lso $(BATS) https://raw.githubusercontent.com/sstephenson/bats/master/libexec/bats
+ chmod 755 $(BIN)/bats*
+
+
+
+# target: check-tools-bash - Check versions of Bash tools.
+.PHONY: check-tools-bash
+check-tools-bash:
+ @$(call HELPTEXT,$@)
+ @$(call CHECK_VERSION, $(SHELLCHECK))
+ @$(call CHECK_VERSION, $(BATS))
+
+
+
+# target: shellcheck - Run shellcheck for bash files.
+.PHONY: shellcheck
+shellcheck:
+ @$(call HELPTEXT,$@)
+ [ ! -f src/*.bash ] || $(SHELLCHECK) --shell=bash src/*.bash
+
+
+
+# target: bats - Run bats for unit testing bash files.
+.PHONY: bats
+bats:
+ @$(call HELPTEXT,$@)
+ [ ! -d bats ] || $(BATS) bats/
+
+
+
+# ------------------------------------------------------------------------
+#
+# Theme
+#
+# target: theme - Do make build install in theme/ if available.
+.PHONY: theme
+theme:
+ @$(call HELPTEXT,$@)
+ [ ! -d theme ] || $(MAKE) --directory=theme build install
+ #[ ! -d theme ] || ( cd theme && make build install )
+
+
+
+# ------------------------------------------------------------------------
+#
+# Cimage
+#
+
+define CIMAGE_CONFIG
+ "development",
+ "image_path" => __DIR__ . "/../img/",
+ "cache_path" => __DIR__ . "/../../cache/cimage/",
+ "autoloader" => __DIR__ . "/../../vendor/autoload.php",
+];
+endef
+export CIMAGE_CONFIG
+
+define GIT_IGNORE_FILES
+# Ignore everything in this directory
+*
+# Except this file
+!.gitignore
+endef
+export GIT_IGNORE_FILES
+
+# target: cimage-update - Install/update Cimage to latest version.
+.PHONY: cimage-update
+cimage-update:
+ @$(call HELPTEXT,$@)
+ composer require mos/cimage
+ install -d htdocs/img htdocs/cimage cache/cimage
+ chmod 777 cache/cimage
+ $(ECHO) "$$GIT_IGNORE_FILES" | bash -c 'cat > cache/cimage/.gitignore'
+ cp vendor/mos/cimage/webroot/img.php htdocs/cimage
+ cp vendor/mos/cimage/webroot/img/car.png htdocs/img/
+ touch htdocs/cimage/img_config.php
+
+# target: cimage-config-create - Create configfile for Cimage.
+.PHONY: cimage-config-create
+cimage-config-create:
+ @$(call HELPTEXT,$@)
+ $(ECHO) "$$CIMAGE_CONFIG" | bash -c 'cat > htdocs/cimage/img_config.php'
+ cat htdocs/cimage/img_config.php
diff --git a/cache/cimage/.gitignore b/cache/cimage/.gitignore
new file mode 100644
index 0000000..5e7d273
--- /dev/null
+++ b/cache/cimage/.gitignore
@@ -0,0 +1,4 @@
+# Ignore everything in this directory
+*
+# Except this file
+!.gitignore
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..249c3f7
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,22 @@
+{
+ "name" : "anax/noname",
+ "description": "Anax scaffolding website for development",
+ "license": "MIT",
+ "require": {
+ "anax/common": "^1.0",
+ "anax/configure": "^1.0",
+ "anax/page": "^1.0",
+ "anax/response": "^1.0",
+ "anax/request": "^1.0",
+ "anax/router": "^1.0",
+ "anax/session": "^1.0",
+ "anax/textfilter": "^1.0",
+ "anax/url": "^1.0",
+ "anax/view": "^1.0",
+ "mos/cimage": "^0.7.20",
+ "symfony/yaml": "^3.3"
+ },
+ "autoload": {
+ "psr-4": {"Anax\\": "src/"}
+ }
+}
diff --git a/config/di.php b/config/di.php
new file mode 100644
index 0000000..622c21e
--- /dev/null
+++ b/config/di.php
@@ -0,0 +1,113 @@
+ [
+ "request" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\Request\Request();
+ $obj->init();
+ return $obj;
+ }
+ ],
+ "response" => [
+ "shared" => true,
+ //"callback" => "\Anax\Response\Response",
+ "callback" => function () {
+ $obj = new \Anax\Response\ResponseUtility();
+ $obj->setDI($this);
+ return $obj;
+ }
+ ],
+ "url" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\Url\Url();
+ $request = $this->get("request");
+ $obj->setSiteUrl($request->getSiteUrl());
+ $obj->setBaseUrl($request->getBaseUrl());
+ $obj->setStaticSiteUrl($request->getSiteUrl());
+ $obj->setStaticBaseUrl($request->getBaseUrl());
+ $obj->setScriptName($request->getScriptName());
+ $obj->configure("url.php");
+ $obj->setDefaultsFromConfiguration();
+ return $obj;
+ }
+ ],
+ "router" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\Route\Router();
+ $obj->setDI($this);
+ $obj->configure("route.php");
+ return $obj;
+ }
+ ],
+ "view" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\View\ViewCollection();
+ $obj->setDI($this);
+ $obj->configure("view.php");
+ return $obj;
+ }
+ ],
+ "viewRenderFile" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\View\ViewRenderFile2();
+ $obj->setDI($this);
+ return $obj;
+ }
+ ],
+ "session" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\Session\SessionConfigurable();
+ $obj->configure("session.php");
+ $obj->start();
+ return $obj;
+ }
+ ],
+ "textfilter" => [
+ "shared" => true,
+ "callback" => "\Anax\TextFilter\TextFilter",
+ ],
+ "page" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\Page\Page();
+ $obj->setDI($this);
+ return $obj;
+ }
+ ],
+ "errorController" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\Page\ErrorController();
+ $obj->setDI($this);
+ return $obj;
+ }
+ ],
+ "debugController" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\Page\DebugController();
+ $obj->setDI($this);
+ return $obj;
+ }
+ ],
+ "flatFileContentController" => [
+ "shared" => true,
+ "callback" => function () {
+ $obj = new \Anax\Page\FlatFileContentController();
+ $obj->setDI($this);
+ return $obj;
+ }
+ ],
+ ],
+];
diff --git a/config/error_reporting.php b/config/error_reporting.php
new file mode 100644
index 0000000..0682b41
--- /dev/null
+++ b/config/error_reporting.php
@@ -0,0 +1,34 @@
+Anax: Uncaught exception:
Line "
+ . $e->getLine()
+ . " in file "
+ . $e->getFile()
+ . "
"
+ . get_class($e)
+ . "
"
+ . $e->getMessage()
+ . "
Code: "
+ . $e->getCode()
+ . "
"
+ . $e->getTraceAsString()
+ . "
";
+});
diff --git a/config/route.php b/config/route.php
new file mode 100644
index 0000000..306c800
--- /dev/null
+++ b/config/route.php
@@ -0,0 +1,37 @@
+ Router::DEVELOPMENT, // default, verbose execeptions
+ //"mode" => Router::PRODUCTION, // exceptions turn into 500
+
+ // Load these routefiles in order specified and optionally mount them
+ // onto a base route.
+ "routeFiles" => [
+ [
+ // These are for internal error handling and exceptions
+ "mount" => null,
+ "file" => __DIR__ . "/route/internal.php",
+ ],
+ [
+ // For debugging and development details on Anax
+ "mount" => "debug",
+ "file" => __DIR__ . "/route/debug.php",
+ ],
+ [
+ // To read flat file content in Markdown from content/
+ "mount" => null,
+ "file" => __DIR__ . "/route/flat-file-content.php",
+ ],
+ // [
+ // // Keep this last since its a catch all
+ // "mount" => null,
+ // "sort" => 999,
+ // "file" => __DIR__ . "/route/404.php",
+ // ],
+ ],
+];
diff --git a/config/route/404.php b/config/route/404.php
new file mode 100644
index 0000000..25590d5
--- /dev/null
+++ b/config/route/404.php
@@ -0,0 +1,14 @@
+ [
+ [
+ "info" => "Catch all and send 404.",
+ "requestMethod" => null,
+ "path" => null,
+ "callable" => ["errorController", "page404"],
+ ],
+ ]
+];
diff --git a/config/route/debug.php b/config/route/debug.php
new file mode 100644
index 0000000..f95e534
--- /dev/null
+++ b/config/route/debug.php
@@ -0,0 +1,20 @@
+ [
+ [
+ "info" => "View details on loaded Anax resources.",
+ "requestMethod" => "GET",
+ "path" => "info",
+ "callable" => ["debugController", "info"],
+ ],
+ [
+ "info" => "Debug and information.",
+ "requestMethod" => "GET",
+ "path" => "view",
+ "callable" => ["debugController", "view"],
+ ],
+ ]
+];
diff --git a/config/route/flat-file-content.php b/config/route/flat-file-content.php
new file mode 100644
index 0000000..4c22703
--- /dev/null
+++ b/config/route/flat-file-content.php
@@ -0,0 +1,14 @@
+ [
+ [
+ "info" => "Flat file content.",
+ "requestMethod" => null,
+ "path" => null,
+ "callable" => ["flatFileContentController", "render"],
+ ],
+ ]
+];
diff --git a/config/route/internal.php b/config/route/internal.php
new file mode 100644
index 0000000..8077925
--- /dev/null
+++ b/config/route/internal.php
@@ -0,0 +1,29 @@
+ [
+ [
+ "info" => "403 Forbidden.",
+ "internal" => true,
+ //"requestMethod" => null,
+ "path" => "403",
+ "callable" => ["errorController", "page403"],
+ ],
+ [
+ "info" => "404 Page not found.",
+ "internal" => true,
+ //"requestMethod" => null,
+ "path" => "404",
+ "callable" => ["errorController", "page404"],
+ ],
+ [
+ "info" => "500 Internal Server Error.",
+ "internal" => true,
+ //"requestMethod" => null,
+ "path" => "500",
+ "callable" => ["errorController", "page500"],
+ ],
+ ]
+ ];
diff --git a/config/session.php b/config/session.php
new file mode 100644
index 0000000..7595508
--- /dev/null
+++ b/config/session.php
@@ -0,0 +1,12 @@
+ preg_replace("/[^a-z\d]/i", "", __DIR__),
+ "name" => preg_replace("/[^a-z\d]/i", "", ANAX_APP_PATH),
+
+];
diff --git a/config/url.php b/config/url.php
new file mode 100644
index 0000000..e62645e
--- /dev/null
+++ b/config/url.php
@@ -0,0 +1,14 @@
+ null,
+ //"baseUrl" => null,
+ //"staticSiteUrl" => null,
+ //"staticBaseUrl" => null,
+ //"scriptName" => null,
+ "urlType" => \Anax\Url\Url::URL_CLEAN,
+ //"urlType" => \Anax\Url\Url::URL_APPEND,
+];
diff --git a/config/view.php b/config/view.php
new file mode 100644
index 0000000..216ebe6
--- /dev/null
+++ b/config/view.php
@@ -0,0 +1,24 @@
+ [
+ ANAX_APP_PATH . "/view",
+ ANAX_INSTALL_PATH . "/view",
+ ANAX_INSTALL_PATH . "/vendor/anax/view/view",
+ ],
+
+ // File suffix for template files
+ //"suffix" => ".tpl.php",
+ "suffix" => ".php",
+
+ // Include files before including the view template file.
+ // Use this to expose helper functions for the view.
+ "include" => [
+ //ANAX_APP_PATH . "/view/function/helper.php",
+ ANAX_INSTALL_PATH . "/vendor/anax/view/src/View/ViewHelperFunctions.php",
+ ]
+];
diff --git a/content/debug.md b/content/debug.md
new file mode 100644
index 0000000..898c6bf
--- /dev/null
+++ b/content/debug.md
@@ -0,0 +1,7 @@
+Debugga och utveckla
+===========================
+
+Du kan använda följande routes för att få hjälp med utveckling och debugging av ditt Anax ramverk.
+
+* [Vilka resurser finns laddade i ramverket](debug/info)
+* [Vyhantering och debugging](debug/view)
diff --git a/content/index.md b/content/index.md
new file mode 100644
index 0000000..1727875
--- /dev/null
+++ b/content/index.md
@@ -0,0 +1,21 @@
+---
+title: "My title"
+...
+Min me-sida i kursen oophp
+=========================
+
+[FIGURE src="image/me.jpg?w=500" caption="Bild på mig"]
+
+Detta är min me-sida i kursen. Denna sidan innehåller en presentation av mig själv. Underhåll denna sidan under hela kursen och uppdatera den efter hand och behov.
+
+Så, en presentation en bra början. Skriv några ord om dig själv. Jag börjar.
+
+Mitt namn är Mikael Roos. Född och uppvuxen i Bankeryd, Småland, strax utanför Jönköping, i ett villaområde som byggdes upp samtidigt som vi flyttade in där. Jag gillade landhockey och har spelat bandy och hockey samt gått bowlinggymnasiet i Nässjö. Jag har varit städare, diskare, kallskänka, servitör och kock. På ett bananskal landade jag i Ronneby när jag började högskolan 1990 där och nu är jag kvar med fru, barn och så vidare.
+
+Programmering har alltid intresserat mig sedan 13-årsåldern och min första dator var en Spectravideo 328 med bandspelare.
+
+Om jag skall nämna någon hobby, förutom webbprogrammering, så får det bli att bära sten på sommarstugetomten, och det finns sten så det räcker och blir över.
+
+Till och från får jag för mig att börja på lite hobbies, ett år satsade jag på pokerspel, ett annat år var det geocaching och sedan turfing. Nu ligger jag lågt med hobbies, men något kanske dyker upp...?
+
+Vi syns och hörs i forum och chatt!
diff --git a/content/lek.md b/content/lek.md
new file mode 100644
index 0000000..a5b2820
--- /dev/null
+++ b/content/lek.md
@@ -0,0 +1,13 @@
+Lek
+===========================
+
+Här kan du länka till dina egna lek-sidor, inom eller utom din me-sida.
+
+Du kan skriva egna routes i filen src/route/app.php
, där finns några routehanterare som du kan utgå ifrån.
+
+* [Hello world](lek/hello-world)
+* [Hello world inuti me-sidan](lek/hello-world-wrap)
+
+Du kan också lägga till vanlig PHP-kod i filer under katalogen htdocs, de kan du köra som vanliga enkla PHP-program.
+
+* [Ett demo skript](demo/demo.php)
diff --git a/content/om.md b/content/om.md
new file mode 100644
index 0000000..f948169
--- /dev/null
+++ b/content/om.md
@@ -0,0 +1,16 @@
+---
+...
+Om
+=========================
+
+Denna webbplatsen är en del av kursen [XXX](https://dbwebb.se/kurser/XXX). Uppdatera så att länken går till kursens hemsida på dwebb.se.
+
+Några egna kloka ord om kursen?
+
+En fin och representativ bild för kursen, enligt ditt egna val.
+
+[FIGURE src=image/car.png?w=300 caption="En fin bil som demobild."]
+
+Länka till [dbwebb kursrepot på GitHub](https://github.com/dbwebbse/XXX).
+
+Länka till [ditt eget repo för me/redovisa på GitHub](https://github.com/XXX/XXX).
diff --git a/content/redovisning.md b/content/redovisning.md
new file mode 100644
index 0000000..cac5cd2
--- /dev/null
+++ b/content/redovisning.md
@@ -0,0 +1,53 @@
+---
+...
+Redovisning
+=========================
+
+
+
+Kmom01
+-------------------------
+
+Här är redovisningstexten
+
+
+
+Kmom02
+-------------------------
+
+Här är redovisningstexten
+
+
+
+Kmom03
+-------------------------
+
+Här är redovisningstexten
+
+
+
+Kmom04
+-------------------------
+
+Här är redovisningstexten
+
+
+
+Kmom05
+-------------------------
+
+Här är redovisningstexten
+
+
+
+Kmom06
+-------------------------
+
+Här är redovisningstexten
+
+
+
+Kmom07-10
+-------------------------
+
+Här är redovisningstexten
diff --git a/htdocs/.htaccess b/htdocs/.htaccess
new file mode 100644
index 0000000..e173e3d
--- /dev/null
+++ b/htdocs/.htaccess
@@ -0,0 +1,28 @@
+#
+# This is a modified rewrite to fit Anax when working on both local development
+# environment and publishing to www.student.bth.se.
+#
+# Do NOT forget to change /~mosstud/ to your own student acronym.
+#
+RewriteEngine on
+
+# Igore real files (images, stylesheets etc.)
+RewriteCond %{REQUEST_FILENAME} -f [OR]
+RewriteCond %{REQUEST_FILENAME} -d
+RewriteRule (.*) - [NC,L]
+
+
+# Rewrite 1 - For request via www.student.bth.se
+RewriteCond %{HTTP_HOST} ^www\.student\.bth\.se$ [NC]
+RewriteRule ^image/(.*)$ /~mosstud/dbwebb-kurser/oophp/me/redovisa/htdocs/cimage/img.php?src=$1 [QSA,NC,L]
+
+RewriteCond %{HTTP_HOST} ^www\.student\.bth\.se$ [NC]
+RewriteRule (.*) /~mosstud/dbwebb-kurser/oophp/me/redovisa/htdocs/index.php/$1 [NC,L]
+
+
+# Rewrite 2 - For other requests
+RewriteCond %{HTTP_HOST} !^www\.student\.bth\.se$ [NC]
+RewriteRule ^image/(.*)$ cimage/img.php?src=$1 [QSA,NC,L]
+
+RewriteCond %{HTTP_HOST} !^www\.student\.bth\.se$ [NC]
+RewriteRule (.*) index.php/$1 [NC,L]
diff --git a/htdocs/.htaccess_anax b/htdocs/.htaccess_anax
new file mode 100644
index 0000000..11a0867
--- /dev/null
+++ b/htdocs/.htaccess_anax
@@ -0,0 +1,14 @@
+#
+# This is a Anax base for rewriting all requests to the frontcontroller
+# index.php, if the target route is not a file or a directory.
+#
+RewriteEngine on
+
+# Rewrite for cimage
+RewriteRule ^image/(.*)$ cimage/img.php?src=$1 [QSA,NC,L]
+
+# Rewrite to Anax frontcontroller
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+
+RewriteRule (.*) index.php/$1 [NC,L]
diff --git a/htdocs/.htaccess_wwwstudent b/htdocs/.htaccess_wwwstudent
new file mode 100644
index 0000000..e173e3d
--- /dev/null
+++ b/htdocs/.htaccess_wwwstudent
@@ -0,0 +1,28 @@
+#
+# This is a modified rewrite to fit Anax when working on both local development
+# environment and publishing to www.student.bth.se.
+#
+# Do NOT forget to change /~mosstud/ to your own student acronym.
+#
+RewriteEngine on
+
+# Igore real files (images, stylesheets etc.)
+RewriteCond %{REQUEST_FILENAME} -f [OR]
+RewriteCond %{REQUEST_FILENAME} -d
+RewriteRule (.*) - [NC,L]
+
+
+# Rewrite 1 - For request via www.student.bth.se
+RewriteCond %{HTTP_HOST} ^www\.student\.bth\.se$ [NC]
+RewriteRule ^image/(.*)$ /~mosstud/dbwebb-kurser/oophp/me/redovisa/htdocs/cimage/img.php?src=$1 [QSA,NC,L]
+
+RewriteCond %{HTTP_HOST} ^www\.student\.bth\.se$ [NC]
+RewriteRule (.*) /~mosstud/dbwebb-kurser/oophp/me/redovisa/htdocs/index.php/$1 [NC,L]
+
+
+# Rewrite 2 - For other requests
+RewriteCond %{HTTP_HOST} !^www\.student\.bth\.se$ [NC]
+RewriteRule ^image/(.*)$ cimage/img.php?src=$1 [QSA,NC,L]
+
+RewriteCond %{HTTP_HOST} !^www\.student\.bth\.se$ [NC]
+RewriteRule (.*) index.php/$1 [NC,L]
diff --git a/htdocs/cimage/img.php b/htdocs/cimage/img.php
new file mode 100644
index 0000000..03b09f6
--- /dev/null
+++ b/htdocs/cimage/img.php
@@ -0,0 +1,1197 @@
+img.php: Uncaught exception: "
+ . $exception->getMessage()
+ . "
"
+ . $exception->getTraceAsString()
+ . "
",
+ 500
+ );
+});
+
+
+
+/**
+ * Get configuration options from file, if the file exists, else use $config
+ * if its defined or create an empty $config.
+ */
+$configFile = __DIR__.'/'.basename(__FILE__, '.php').'_config.php';
+
+if (is_file($configFile)) {
+ $config = require $configFile;
+} elseif (!isset($config)) {
+ $config = array();
+}
+
+// Make CIMAGE_DEBUG false by default, if not already defined
+if (!defined("CIMAGE_DEBUG")) {
+ define("CIMAGE_DEBUG", false);
+}
+
+
+
+/**
+ * Setup the autoloader, but not when using a bundle.
+ */
+if (!defined("CIMAGE_BUNDLE")) {
+ if (!isset($config["autoloader"])) {
+ die("CImage: Missing autoloader.");
+ }
+
+ require $config["autoloader"];
+}
+
+
+
+/**
+* verbose, v - do a verbose dump of what happens
+* vf - do verbose dump to file
+*/
+$verbose = getDefined(array('verbose', 'v'), true, false);
+$verboseFile = getDefined('vf', true, false);
+verbose("img.php version = " . CIMAGE_VERSION);
+
+
+
+/**
+* status - do a verbose dump of the configuration
+*/
+$status = getDefined('status', true, false);
+
+
+
+/**
+ * Set mode as strict, production or development.
+ * Default is production environment.
+ */
+$mode = getConfig('mode', 'production');
+
+// Settings for any mode
+set_time_limit(20);
+ini_set('gd.jpeg_ignore_warning', 1);
+
+if (!extension_loaded('gd')) {
+ errorPage("Extension gd is not loaded.", 500);
+}
+
+// Specific settings for each mode
+if ($mode == 'strict') {
+
+ error_reporting(0);
+ ini_set('display_errors', 0);
+ ini_set('log_errors', 1);
+ $verbose = false;
+ $status = false;
+ $verboseFile = false;
+
+} elseif ($mode == 'production') {
+
+ error_reporting(-1);
+ ini_set('display_errors', 0);
+ ini_set('log_errors', 1);
+ $verbose = false;
+ $status = false;
+ $verboseFile = false;
+
+} elseif ($mode == 'development') {
+
+ error_reporting(-1);
+ ini_set('display_errors', 1);
+ ini_set('log_errors', 0);
+ $verboseFile = false;
+
+} elseif ($mode == 'test') {
+
+ error_reporting(-1);
+ ini_set('display_errors', 1);
+ ini_set('log_errors', 0);
+
+} else {
+ errorPage("Unknown mode: $mode", 500);
+}
+
+verbose("mode = $mode");
+verbose("error log = " . ini_get('error_log'));
+
+
+
+/**
+ * Set default timezone if not set or if its set in the config-file.
+ */
+$defaultTimezone = getConfig('default_timezone', null);
+
+if ($defaultTimezone) {
+ date_default_timezone_set($defaultTimezone);
+} elseif (!ini_get('default_timezone')) {
+ date_default_timezone_set('UTC');
+}
+
+
+
+/**
+ * Check if passwords are configured, used and match.
+ * Options decide themself if they require passwords to be used.
+ */
+$pwdConfig = getConfig('password', false);
+$pwdAlways = getConfig('password_always', false);
+$pwdType = getConfig('password_type', 'text');
+$pwd = get(array('password', 'pwd'), null);
+
+// Check if passwords match, if configured to use passwords
+$passwordMatch = null;
+if ($pwd) {
+ switch ($pwdType) {
+ case 'md5':
+ $passwordMatch = ($pwdConfig === md5($pwd));
+ break;
+ case 'hash':
+ $passwordMatch = password_verify($pwd, $pwdConfig);
+ break;
+ case 'text':
+ $passwordMatch = ($pwdConfig === $pwd);
+ break;
+ default:
+ $passwordMatch = false;
+ }
+}
+
+if ($pwdAlways && $passwordMatch !== true) {
+ errorPage("Password required and does not match or exists.", 403);
+}
+
+verbose("password match = $passwordMatch");
+
+
+
+/**
+ * Prevent hotlinking, leeching, of images by controlling who access them
+ * from where.
+ *
+ */
+$allowHotlinking = getConfig('allow_hotlinking', true);
+$hotlinkingWhitelist = getConfig('hotlinking_whitelist', array());
+
+$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null;
+$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
+$refererHost = parse_url($referer, PHP_URL_HOST);
+
+if (!$allowHotlinking) {
+ if ($passwordMatch) {
+ ; // Always allow when password match
+ verbose("Hotlinking since passwordmatch");
+ } elseif ($passwordMatch === false) {
+ errorPage("Hotlinking/leeching not allowed when password missmatch.", 403);
+ } elseif (!$referer) {
+ errorPage("Hotlinking/leeching not allowed and referer is missing.", 403);
+ } elseif (strcmp($serverName, $refererHost) == 0) {
+ ; // Allow when serverName matches refererHost
+ verbose("Hotlinking disallowed but serverName matches refererHost.");
+ } elseif (!empty($hotlinkingWhitelist)) {
+ $whitelist = new CWhitelist();
+ $allowedByWhitelist = $whitelist->check($refererHost, $hotlinkingWhitelist);
+
+ if ($allowedByWhitelist) {
+ verbose("Hotlinking/leeching allowed by whitelist.");
+ } else {
+ errorPage("Hotlinking/leeching not allowed by whitelist. Referer: $referer.", 403);
+ }
+
+ } else {
+ errorPage("Hotlinking/leeching not allowed.", 403);
+ }
+}
+
+verbose("allow_hotlinking = $allowHotlinking");
+verbose("referer = $referer");
+verbose("referer host = $refererHost");
+
+
+
+/**
+ * Create the class for the image.
+ */
+$CImage = getConfig('CImage', 'CImage');
+$img = new $CImage();
+$img->setVerbose($verbose || $verboseFile);
+
+
+
+/**
+ * Get the cachepath from config.
+ */
+$CCache = getConfig('CCache', 'CCache');
+$cachePath = getConfig('cache_path', __DIR__ . '/../cache/');
+$cache = new $CCache();
+$cache->setDir($cachePath);
+
+
+
+/**
+ * no-cache, nc - skip the cached version and process and create a new version in cache.
+ */
+$useCache = getDefined(array('no-cache', 'nc'), false, true);
+
+verbose("use cache = $useCache");
+
+
+
+/**
+ * Prepare fast track cache for swriting cache items.
+ */
+$fastTrackCache = "fasttrack";
+$allowFastTrackCache = getConfig('fast_track_allow', false);
+
+$CFastTrackCache = getConfig('CFastTrackCache', 'CFastTrackCache');
+$ftc = new $CFastTrackCache();
+$ftc->setCacheDir($cache->getPathToSubdir($fastTrackCache))
+ ->enable($allowFastTrackCache)
+ ->setFilename(array('no-cache', 'nc'));
+$img->injectDependency("fastTrackCache", $ftc);
+
+
+
+/**
+ * Load and output images from fast track cache, if items are available
+ * in cache.
+ */
+if ($useCache && $allowFastTrackCache) {
+ if (CIMAGE_DEBUG) {
+ trace("img.php fast track cache enabled and used");
+ }
+ $ftc->output();
+}
+
+
+
+/**
+ * Allow or disallow remote download of images from other servers.
+ * Passwords apply if used.
+ *
+ */
+$allowRemote = getConfig('remote_allow', false);
+
+if ($allowRemote && $passwordMatch !== false) {
+ $cacheRemote = $cache->getPathToSubdir("remote");
+
+ $pattern = getConfig('remote_pattern', null);
+ $img->setRemoteDownload($allowRemote, $cacheRemote, $pattern);
+
+ $whitelist = getConfig('remote_whitelist', null);
+ $img->setRemoteHostWhitelist($whitelist);
+}
+
+
+
+/**
+ * shortcut, sc - extend arguments with a constant value, defined
+ * in config-file.
+ */
+$shortcut = get(array('shortcut', 'sc'), null);
+$shortcutConfig = getConfig('shortcut', array(
+ 'sepia' => "&f=grayscale&f0=brightness,-10&f1=contrast,-20&f2=colorize,120,60,0,0&sharpen",
+));
+
+verbose("shortcut = $shortcut");
+
+if (isset($shortcut)
+ && isset($shortcutConfig[$shortcut])) {
+
+ parse_str($shortcutConfig[$shortcut], $get);
+ verbose("shortcut-constant = {$shortcutConfig[$shortcut]}");
+ $_GET = array_merge($_GET, $get);
+}
+
+
+
+/**
+ * src - the source image file.
+ */
+$srcImage = urldecode(get('src'))
+ or errorPage('Must set src-attribute.', 404);
+
+// Get settings for src-alt as backup image
+$srcAltImage = urldecode(get('src-alt', null));
+$srcAltConfig = getConfig('src_alt', null);
+if (empty($srcAltImage)) {
+ $srcAltImage = $srcAltConfig;
+}
+
+// Check for valid/invalid characters
+$imagePath = getConfig('image_path', __DIR__ . '/img/');
+$imagePathConstraint = getConfig('image_path_constraint', true);
+$validFilename = getConfig('valid_filename', '#^[a-z0-9A-Z-/_ \.:]+$#');
+
+// Source is remote
+$remoteSource = false;
+
+// Dummy image feature
+$dummyEnabled = getConfig('dummy_enabled', true);
+$dummyFilename = getConfig('dummy_filename', 'dummy');
+$dummyImage = false;
+
+preg_match($validFilename, $srcImage)
+ or errorPage('Source filename contains invalid characters.', 404);
+
+if ($dummyEnabled && $srcImage === $dummyFilename) {
+
+ // Prepare to create a dummy image and use it as the source image.
+ $dummyImage = true;
+
+} elseif ($allowRemote && $img->isRemoteSource($srcImage)) {
+
+ // If source is a remote file, ignore local file checks.
+ $remoteSource = true;
+
+} else {
+
+ // Check if file exists on disk or try using src-alt
+ $pathToImage = realpath($imagePath . $srcImage);
+
+ if (!is_file($pathToImage) && !empty($srcAltImage)) {
+ // Try using the src-alt instead
+ $srcImage = $srcAltImage;
+ $pathToImage = realpath($imagePath . $srcImage);
+
+ preg_match($validFilename, $srcImage)
+ or errorPage('Source (alt) filename contains invalid characters.', 404);
+
+ if ($dummyEnabled && $srcImage === $dummyFilename) {
+ // Check if src-alt is the dummy image
+ $dummyImage = true;
+ }
+ }
+
+ if (!$dummyImage) {
+ is_file($pathToImage)
+ or errorPage(
+ 'Source image is not a valid file, check the filename and that a
+ matching file exists on the filesystem.',
+ 404
+ );
+ }
+}
+
+if ($imagePathConstraint && !$dummyImage && !$remoteSource) {
+ // Check that the image is a file below the directory 'image_path'.
+ $imageDir = realpath($imagePath);
+
+ substr_compare($imageDir, $pathToImage, 0, strlen($imageDir)) == 0
+ or errorPage(
+ 'Security constraint: Source image is not below the directory "image_path"
+ as specified in the config file img_config.php.',
+ 404
+ );
+}
+
+verbose("src = $srcImage");
+
+
+
+/**
+ * Manage size constants from config file, use constants to replace values
+ * for width and height.
+ */
+$sizeConstant = getConfig('size_constant', function () {
+
+ // Set sizes to map constant to value, easier to use with width or height
+ $sizes = array(
+ 'w1' => 613,
+ 'w2' => 630,
+ );
+
+ // Add grid column width, useful for use as predefined size for width (or height).
+ $gridColumnWidth = 30;
+ $gridGutterWidth = 10;
+ $gridColumns = 24;
+
+ for ($i = 1; $i <= $gridColumns; $i++) {
+ $sizes['c' . $i] = ($gridColumnWidth + $gridGutterWidth) * $i - $gridGutterWidth;
+ }
+
+ return $sizes;
+});
+
+$sizes = call_user_func($sizeConstant);
+
+
+
+/**
+ * width, w - set target width, affecting the resulting image width, height and resize options
+ */
+$newWidth = get(array('width', 'w'));
+$maxWidth = getConfig('max_width', 2000);
+
+// Check to replace predefined size
+if (isset($sizes[$newWidth])) {
+ $newWidth = $sizes[$newWidth];
+}
+
+// Support width as % of original width
+if ($newWidth[strlen($newWidth)-1] == '%') {
+ is_numeric(substr($newWidth, 0, -1))
+ or errorPage('Width % not numeric.', 404);
+} else {
+ is_null($newWidth)
+ or ($newWidth > 10 && $newWidth <= $maxWidth)
+ or errorPage('Width out of range.', 404);
+}
+
+verbose("new width = $newWidth");
+
+
+
+/**
+ * height, h - set target height, affecting the resulting image width, height and resize options
+ */
+$newHeight = get(array('height', 'h'));
+$maxHeight = getConfig('max_height', 2000);
+
+// Check to replace predefined size
+if (isset($sizes[$newHeight])) {
+ $newHeight = $sizes[$newHeight];
+}
+
+// height
+if ($newHeight[strlen($newHeight)-1] == '%') {
+ is_numeric(substr($newHeight, 0, -1))
+ or errorPage('Height % out of range.', 404);
+} else {
+ is_null($newHeight)
+ or ($newHeight > 10 && $newHeight <= $maxHeight)
+ or errorPage('Height out of range.', 404);
+}
+
+verbose("new height = $newHeight");
+
+
+
+/**
+ * aspect-ratio, ar - affecting the resulting image width, height and resize options
+ */
+$aspectRatio = get(array('aspect-ratio', 'ar'));
+$aspectRatioConstant = getConfig('aspect_ratio_constant', function () {
+ return array(
+ '3:1' => 3/1,
+ '3:2' => 3/2,
+ '4:3' => 4/3,
+ '8:5' => 8/5,
+ '16:10' => 16/10,
+ '16:9' => 16/9,
+ 'golden' => 1.618,
+ );
+});
+
+// Check to replace predefined aspect ratio
+$aspectRatios = call_user_func($aspectRatioConstant);
+$negateAspectRatio = ($aspectRatio[0] == '!') ? true : false;
+$aspectRatio = $negateAspectRatio ? substr($aspectRatio, 1) : $aspectRatio;
+
+if (isset($aspectRatios[$aspectRatio])) {
+ $aspectRatio = $aspectRatios[$aspectRatio];
+}
+
+if ($negateAspectRatio) {
+ $aspectRatio = 1 / $aspectRatio;
+}
+
+is_null($aspectRatio)
+ or is_numeric($aspectRatio)
+ or errorPage('Aspect ratio out of range', 404);
+
+verbose("aspect ratio = $aspectRatio");
+
+
+
+/**
+ * crop-to-fit, cf - affecting the resulting image width, height and resize options
+ */
+$cropToFit = getDefined(array('crop-to-fit', 'cf'), true, false);
+
+verbose("crop to fit = $cropToFit");
+
+
+
+/**
+ * Set default background color from config file.
+ */
+$backgroundColor = getConfig('background_color', null);
+
+if ($backgroundColor) {
+ $img->setDefaultBackgroundColor($backgroundColor);
+ verbose("Using default background_color = $backgroundColor");
+}
+
+
+
+/**
+ * bgColor - Default background color to use
+ */
+$bgColor = get(array('bgColor', 'bg-color', 'bgc'), null);
+
+verbose("bgColor = $bgColor");
+
+
+
+/**
+ * Do or do not resample image when resizing.
+ */
+$resizeStrategy = getDefined(array('no-resample'), true, false);
+
+if ($resizeStrategy) {
+ $img->setCopyResizeStrategy($img::RESIZE);
+ verbose("Setting = Resize instead of resample");
+}
+
+
+
+
+/**
+ * fill-to-fit, ff - affecting the resulting image width, height and resize options
+ */
+$fillToFit = get(array('fill-to-fit', 'ff'), null);
+
+verbose("fill-to-fit = $fillToFit");
+
+if ($fillToFit !== null) {
+
+ if (!empty($fillToFit)) {
+ $bgColor = $fillToFit;
+ verbose("fillToFit changed bgColor to = $bgColor");
+ }
+
+ $fillToFit = true;
+ verbose("fill-to-fit (fixed) = $fillToFit");
+}
+
+
+
+/**
+ * no-ratio, nr, stretch - affecting the resulting image width, height and resize options
+ */
+$keepRatio = getDefined(array('no-ratio', 'nr', 'stretch'), false, true);
+
+verbose("keep ratio = $keepRatio");
+
+
+
+/**
+ * crop, c - affecting the resulting image width, height and resize options
+ */
+$crop = get(array('crop', 'c'));
+
+verbose("crop = $crop");
+
+
+
+/**
+ * area, a - affecting the resulting image width, height and resize options
+ */
+$area = get(array('area', 'a'));
+
+verbose("area = $area");
+
+
+
+/**
+ * skip-original, so - skip the original image and always process a new image
+ */
+$useOriginal = getDefined(array('skip-original', 'so'), false, true);
+$useOriginalDefault = getConfig('skip_original', false);
+
+if ($useOriginalDefault === true) {
+ verbose("skip original is default ON");
+ $useOriginal = false;
+}
+
+verbose("use original = $useOriginal");
+
+
+
+/**
+ * quality, q - set level of quality for jpeg images
+ */
+$quality = get(array('quality', 'q'));
+$qualityDefault = getConfig('jpg_quality', null);
+
+is_null($quality)
+ or ($quality > 0 and $quality <= 100)
+ or errorPage('Quality out of range', 404);
+
+if (is_null($quality) && !is_null($qualityDefault)) {
+ $quality = $qualityDefault;
+}
+
+verbose("quality = $quality");
+
+
+
+/**
+ * compress, co - what strategy to use when compressing png images
+ */
+$compress = get(array('compress', 'co'));
+$compressDefault = getConfig('png_compression', null);
+
+is_null($compress)
+ or ($compress > 0 and $compress <= 9)
+ or errorPage('Compress out of range', 404);
+
+if (is_null($compress) && !is_null($compressDefault)) {
+ $compress = $compressDefault;
+}
+
+verbose("compress = $compress");
+
+
+
+/**
+ * save-as, sa - what type of image to save
+ */
+$saveAs = get(array('save-as', 'sa'));
+
+verbose("save as = $saveAs");
+
+
+
+/**
+ * scale, s - Processing option, scale up or down the image prior actual resize
+ */
+$scale = get(array('scale', 's'));
+
+is_null($scale)
+ or ($scale >= 0 and $scale <= 400)
+ or errorPage('Scale out of range', 404);
+
+verbose("scale = $scale");
+
+
+
+/**
+ * palette, p - Processing option, create a palette version of the image
+ */
+$palette = getDefined(array('palette', 'p'), true, false);
+
+verbose("palette = $palette");
+
+
+
+/**
+ * sharpen - Processing option, post filter for sharpen effect
+ */
+$sharpen = getDefined('sharpen', true, null);
+
+verbose("sharpen = $sharpen");
+
+
+
+/**
+ * emboss - Processing option, post filter for emboss effect
+ */
+$emboss = getDefined('emboss', true, null);
+
+verbose("emboss = $emboss");
+
+
+
+/**
+ * blur - Processing option, post filter for blur effect
+ */
+$blur = getDefined('blur', true, null);
+
+verbose("blur = $blur");
+
+
+
+/**
+ * rotateBefore - Rotate the image with an angle, before processing
+ */
+$rotateBefore = get(array('rotateBefore', 'rotate-before', 'rb'));
+
+is_null($rotateBefore)
+ or ($rotateBefore >= -360 and $rotateBefore <= 360)
+ or errorPage('RotateBefore out of range', 404);
+
+verbose("rotateBefore = $rotateBefore");
+
+
+
+/**
+ * rotateAfter - Rotate the image with an angle, before processing
+ */
+$rotateAfter = get(array('rotateAfter', 'rotate-after', 'ra', 'rotate', 'r'));
+
+is_null($rotateAfter)
+ or ($rotateAfter >= -360 and $rotateAfter <= 360)
+ or errorPage('RotateBefore out of range', 404);
+
+verbose("rotateAfter = $rotateAfter");
+
+
+
+/**
+ * autoRotate - Auto rotate based on EXIF information
+ */
+$autoRotate = getDefined(array('autoRotate', 'auto-rotate', 'aro'), true, false);
+
+verbose("autoRotate = $autoRotate");
+
+
+
+/**
+ * filter, f, f0-f9 - Processing option, post filter for various effects using imagefilter()
+ */
+$filters = array();
+$filter = get(array('filter', 'f'));
+if ($filter) {
+ $filters[] = $filter;
+}
+
+for ($i = 0; $i < 10; $i++) {
+ $filter = get(array("filter{$i}", "f{$i}"));
+ if ($filter) {
+ $filters[] = $filter;
+ }
+}
+
+verbose("filters = " . print_r($filters, 1));
+
+
+
+/**
+* json - output the image as a JSON object with details on the image.
+* ascii - output the image as ASCII art.
+ */
+$outputFormat = getDefined('json', 'json', null);
+$outputFormat = getDefined('ascii', 'ascii', $outputFormat);
+
+verbose("outputformat = $outputFormat");
+
+if ($outputFormat == 'ascii') {
+ $defaultOptions = getConfig(
+ 'ascii-options',
+ array(
+ "characterSet" => 'two',
+ "scale" => 14,
+ "luminanceStrategy" => 3,
+ "customCharacterSet" => null,
+ )
+ );
+ $options = get('ascii');
+ $options = explode(',', $options);
+
+ if (isset($options[0]) && !empty($options[0])) {
+ $defaultOptions['characterSet'] = $options[0];
+ }
+
+ if (isset($options[1]) && !empty($options[1])) {
+ $defaultOptions['scale'] = $options[1];
+ }
+
+ if (isset($options[2]) && !empty($options[2])) {
+ $defaultOptions['luminanceStrategy'] = $options[2];
+ }
+
+ if (count($options) > 3) {
+ // Last option is custom character string
+ unset($options[0]);
+ unset($options[1]);
+ unset($options[2]);
+ $characterString = implode($options);
+ $defaultOptions['customCharacterSet'] = $characterString;
+ }
+
+ $img->setAsciiOptions($defaultOptions);
+}
+
+
+
+
+/**
+ * dpr - change to get larger image to easier support larger dpr, such as retina.
+ */
+$dpr = get(array('ppi', 'dpr', 'device-pixel-ratio'), 1);
+
+verbose("dpr = $dpr");
+
+
+
+/**
+ * convolve - image convolution as in http://php.net/manual/en/function.imageconvolution.php
+ */
+$convolve = get('convolve', null);
+$convolutionConstant = getConfig('convolution_constant', array());
+
+// Check if the convolve is matching an existing constant
+if ($convolve && isset($convolutionConstant)) {
+ $img->addConvolveExpressions($convolutionConstant);
+ verbose("convolve constant = " . print_r($convolutionConstant, 1));
+}
+
+verbose("convolve = " . print_r($convolve, 1));
+
+
+
+/**
+ * no-upscale, nu - Do not upscale smaller image to larger dimension.
+ */
+$upscale = getDefined(array('no-upscale', 'nu'), false, true);
+
+verbose("upscale = $upscale");
+
+
+
+/**
+ * Get details for post processing
+ */
+$postProcessing = getConfig('postprocessing', array(
+ 'png_lossy' => false,
+ 'png_lossy_cmd' => '/usr/local/bin/pngquant --force --output',
+
+ 'png_filter' => false,
+ 'png_filter_cmd' => '/usr/local/bin/optipng -q',
+
+ 'png_deflate' => false,
+ 'png_deflate_cmd' => '/usr/local/bin/pngout -q',
+
+ 'jpeg_optimize' => false,
+ 'jpeg_optimize_cmd' => '/usr/local/bin/jpegtran -copy none -optimize',
+));
+
+
+
+/**
+ * lossy - Do lossy postprocessing, if available.
+ */
+$lossy = getDefined(array('lossy'), true, null);
+
+verbose("lossy = $lossy");
+
+
+
+/**
+ * alias - Save resulting image to another alias name.
+ * Password always apply, must be defined.
+ */
+$alias = get('alias', null);
+$aliasPath = getConfig('alias_path', null);
+$validAliasname = getConfig('valid_aliasname', '#^[a-z0-9A-Z-_]+$#');
+$aliasTarget = null;
+
+if ($alias && $aliasPath && $passwordMatch) {
+
+ $aliasTarget = $aliasPath . $alias;
+ $useCache = false;
+
+ is_writable($aliasPath)
+ or errorPage("Directory for alias is not writable.", 403);
+
+ preg_match($validAliasname, $alias)
+ or errorPage('Filename for alias contains invalid characters. Do not add extension.', 404);
+
+} elseif ($alias) {
+ errorPage('Alias is not enabled in the config file or password not matching.', 403);
+}
+
+verbose("alias = $alias");
+
+
+
+/**
+ * Add cache control HTTP header.
+ */
+$cacheControl = getConfig('cache_control', null);
+
+if ($cacheControl) {
+ verbose("cacheControl = $cacheControl");
+ $img->addHTTPHeader("Cache-Control", $cacheControl);
+}
+
+
+
+/**
+ * Prepare a dummy image and use it as source image.
+ */
+if ($dummyImage === true) {
+ $dummyDir = $cache->getPathToSubdir("dummy");
+
+ $img->setSaveFolder($dummyDir)
+ ->setSource($dummyFilename, $dummyDir)
+ ->setOptions(
+ array(
+ 'newWidth' => $newWidth,
+ 'newHeight' => $newHeight,
+ 'bgColor' => $bgColor,
+ )
+ )
+ ->setJpegQuality($quality)
+ ->setPngCompression($compress)
+ ->createDummyImage()
+ ->generateFilename(null, false)
+ ->save(null, null, false);
+
+ $srcImage = $img->getTarget();
+ $imagePath = null;
+
+ verbose("src (updated) = $srcImage");
+}
+
+
+
+/**
+ * Prepare a sRGB version of the image and use it as source image.
+ */
+$srgbDefault = getConfig('srgb_default', false);
+$srgbColorProfile = getConfig('srgb_colorprofile', __DIR__ . '/../icc/sRGB_IEC61966-2-1_black_scaled.icc');
+$srgb = getDefined('srgb', true, null);
+
+if ($srgb || $srgbDefault) {
+
+ $filename = $img->convert2sRGBColorSpace(
+ $srcImage,
+ $imagePath,
+ $cache->getPathToSubdir("srgb"),
+ $srgbColorProfile,
+ $useCache
+ );
+
+ if ($filename) {
+ $srcImage = $img->getTarget();
+ $imagePath = null;
+ verbose("srgb conversion and saved to cache = $srcImage");
+ } else {
+ verbose("srgb not op");
+ }
+}
+
+
+
+/**
+ * Display status
+ */
+if ($status) {
+ $text = "img.php version = " . CIMAGE_VERSION . "\n";
+ $text .= "PHP version = " . PHP_VERSION . "\n";
+ $text .= "Running on: " . $_SERVER['SERVER_SOFTWARE'] . "\n";
+ $text .= "Allow remote images = $allowRemote\n";
+
+ $res = $cache->getStatusOfSubdir("");
+ $text .= "Cache $res\n";
+
+ $res = $cache->getStatusOfSubdir("remote");
+ $text .= "Cache remote $res\n";
+
+ $res = $cache->getStatusOfSubdir("dummy");
+ $text .= "Cache dummy $res\n";
+
+ $res = $cache->getStatusOfSubdir("srgb");
+ $text .= "Cache srgb $res\n";
+
+ $res = $cache->getStatusOfSubdir($fastTrackCache);
+ $text .= "Cache fasttrack $res\n";
+
+ $text .= "Alias path writable = " . is_writable($aliasPath) . "\n";
+
+ $no = extension_loaded('exif') ? null : 'NOT';
+ $text .= "Extension exif is $no loaded.
";
+
+ $no = extension_loaded('curl') ? null : 'NOT';
+ $text .= "Extension curl is $no loaded.
";
+
+ $no = extension_loaded('imagick') ? null : 'NOT';
+ $text .= "Extension imagick is $no loaded.
";
+
+ $no = extension_loaded('gd') ? null : 'NOT';
+ $text .= "Extension gd is $no loaded.
";
+
+ $text .= checkExternalCommand("PNG LOSSY", $postProcessing["png_lossy"], $postProcessing["png_lossy_cmd"]);
+ $text .= checkExternalCommand("PNG FILTER", $postProcessing["png_filter"], $postProcessing["png_filter_cmd"]);
+ $text .= checkExternalCommand("PNG DEFLATE", $postProcessing["png_deflate"], $postProcessing["png_deflate_cmd"]);
+ $text .= checkExternalCommand("JPEG OPTIMIZE", $postProcessing["jpeg_optimize"], $postProcessing["jpeg_optimize_cmd"]);
+
+ if (!$no) {
+ $text .= print_r(gd_info(), 1);
+ }
+
+ echo <<
+
+
+CImage status
+$text
+EOD;
+ exit;
+}
+
+
+
+/**
+ * Log verbose details to file
+ */
+if ($verboseFile) {
+ $img->setVerboseToFile("$cachePath/log.txt");
+}
+
+
+
+/**
+ * Hook after img.php configuration and before processing with CImage
+ */
+$hookBeforeCImage = getConfig('hook_before_CImage', null);
+
+if (is_callable($hookBeforeCImage)) {
+ verbose("hookBeforeCImage activated");
+
+ $allConfig = $hookBeforeCImage($img, array(
+ // Options for calculate dimensions
+ 'newWidth' => $newWidth,
+ 'newHeight' => $newHeight,
+ 'aspectRatio' => $aspectRatio,
+ 'keepRatio' => $keepRatio,
+ 'cropToFit' => $cropToFit,
+ 'fillToFit' => $fillToFit,
+ 'crop' => $crop,
+ 'area' => $area,
+ 'upscale' => $upscale,
+
+ // Pre-processing, before resizing is done
+ 'scale' => $scale,
+ 'rotateBefore' => $rotateBefore,
+ 'autoRotate' => $autoRotate,
+
+ // General processing options
+ 'bgColor' => $bgColor,
+
+ // Post-processing, after resizing is done
+ 'palette' => $palette,
+ 'filters' => $filters,
+ 'sharpen' => $sharpen,
+ 'emboss' => $emboss,
+ 'blur' => $blur,
+ 'convolve' => $convolve,
+ 'rotateAfter' => $rotateAfter,
+
+ // Output format
+ 'outputFormat' => $outputFormat,
+ 'dpr' => $dpr,
+
+ // Other
+ 'postProcessing' => $postProcessing,
+ 'lossy' => $lossy,
+ ));
+ verbose(print_r($allConfig, 1));
+ extract($allConfig);
+}
+
+
+
+/**
+ * Display image if verbose mode
+ */
+if ($verbose) {
+ $query = array();
+ parse_str($_SERVER['QUERY_STRING'], $query);
+ unset($query['verbose']);
+ unset($query['v']);
+ unset($query['nocache']);
+ unset($query['nc']);
+ unset($query['json']);
+ $url1 = '?' . htmlentities(urldecode(http_build_query($query)));
+ $url2 = '?' . urldecode(http_build_query($query));
+ echo <<
+
+
+CImage verbose output
+
+$url1
+
+
+
+
+
+EOD;
+}
+
+
+
+/**
+ * Load, process and output the image
+ */
+$img->log("Incoming arguments: " . print_r(verbose(), 1))
+ ->setSaveFolder($cachePath)
+ ->useCache($useCache)
+ ->setSource($srcImage, $imagePath)
+ ->setOptions(
+ array(
+ // Options for calculate dimensions
+ 'newWidth' => $newWidth,
+ 'newHeight' => $newHeight,
+ 'aspectRatio' => $aspectRatio,
+ 'keepRatio' => $keepRatio,
+ 'cropToFit' => $cropToFit,
+ 'fillToFit' => $fillToFit,
+ 'crop' => $crop,
+ 'area' => $area,
+ 'upscale' => $upscale,
+
+ // Pre-processing, before resizing is done
+ 'scale' => $scale,
+ 'rotateBefore' => $rotateBefore,
+ 'autoRotate' => $autoRotate,
+
+ // General processing options
+ 'bgColor' => $bgColor,
+
+ // Post-processing, after resizing is done
+ 'palette' => $palette,
+ 'filters' => $filters,
+ 'sharpen' => $sharpen,
+ 'emboss' => $emboss,
+ 'blur' => $blur,
+ 'convolve' => $convolve,
+ 'rotateAfter' => $rotateAfter,
+
+ // Output format
+ 'outputFormat' => $outputFormat,
+ 'dpr' => $dpr,
+
+ // Postprocessing using external tools
+ 'lossy' => $lossy,
+ )
+ )
+ ->loadImageDetails()
+ ->initDimensions()
+ ->calculateNewWidthAndHeight()
+ ->setSaveAsExtension($saveAs)
+ ->setJpegQuality($quality)
+ ->setPngCompression($compress)
+ ->useOriginalIfPossible($useOriginal)
+ ->generateFilename($cachePath)
+ ->useCacheIfPossible($useCache)
+ ->load()
+ ->preResize()
+ ->resize()
+ ->postResize()
+ ->setPostProcessingOptions($postProcessing)
+ ->save()
+ ->linkToCacheFile($aliasTarget)
+ ->output();
diff --git a/htdocs/cimage/img_config.php b/htdocs/cimage/img_config.php
new file mode 100644
index 0000000..f3b6730
--- /dev/null
+++ b/htdocs/cimage/img_config.php
@@ -0,0 +1,7 @@
+ "development",
+ "image_path" => __DIR__ . "/../img/",
+ "cache_path" => __DIR__ . "/../../cache/cimage/",
+ "autoloader" => __DIR__ . "/../../vendor/autoload.php",
+];
diff --git a/htdocs/css/style.css b/htdocs/css/style.css
new file mode 100644
index 0000000..3a14e1f
--- /dev/null
+++ b/htdocs/css/style.css
@@ -0,0 +1,113 @@
+/**
+ * General setup for layout.
+ */
+html {
+ overflow-y: scroll;
+ background-color: #424242;
+}
+
+body {
+ margin: 0;
+ background-color: #fff;
+ word-wrap: break-word;
+}
+
+.outer-wrap {
+ margin: 0 auto;
+ background-color: #fff;
+}
+
+.inner-wrap {
+ margin: 0 auto;
+ max-width: 680px;
+ padding: 0 0.5em;
+}
+
+
+
+/**
+ * Header
+ */
+.outer-wrap-header {
+ max-width: 100%;
+ min-height: 2em;
+ background-color: #000;
+ color: #fff;
+}
+
+.outer-wrap-header {
+ position: relative;
+}
+
+.inner-wrap-header {
+ max-width: 100%;
+}
+
+.header-logo {
+ position: absolute;
+ top: 7em;
+ left: 1em;
+}
+
+
+
+/**
+ * Navbar
+ */
+.outer-wrap-navbar {
+ max-width: 100%;
+ min-height: 2em;
+ background-color: #535353;
+ color: #fff;
+ padding: 0.5em 0;
+}
+
+.outer-wrap-navbar a {
+ color: #fff;
+}
+
+.outer-wrap-navbar a:hover {
+ color: #ddd;
+}
+
+
+
+/**
+ * Main
+ */
+.outer-wrap-main {
+ min-height: 20em;
+ margin-bottom: 2em;
+}
+
+.wrap-main h1 {
+ border-bottom: 1px solid #999;
+}
+
+.wrap-main h2 {
+ border-bottom: 1px solid #ccc;
+}
+
+
+
+/**
+ * Footer
+ */
+.outer-wrap-footer {
+ max-width: 100%;
+ min-height: 10em;
+ background-color: #424242;
+ color: #fff;
+ padding: 1em 0;
+}
+
+
+
+/**
+ * Responsive
+ */
+@media screen and (max-width: 970px) {
+ .header-logo {
+ display: none;
+ }
+}
diff --git a/htdocs/demo/demo.php b/htdocs/demo/demo.php
new file mode 100644
index 0000000..69fa86e
--- /dev/null
+++ b/htdocs/demo/demo.php
@@ -0,0 +1,4 @@
+Just to show off how to write and execute a standalone PHP file outside the framework.
diff --git a/htdocs/favicon.ico b/htdocs/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..60d05ef23d01a20ba5b861cdfab9ba6b1a42e402
GIT binary patch
literal 32988
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
XU=Q`&(*Toy=O#&iBb1QQI1OfqP
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
literal 0
HcmV?d00001
diff --git a/htdocs/img/car.png b/htdocs/img/car.png
new file mode 100644
index 0000000000000000000000000000000000000000..b9c643f540a6297bdad64c11cd88140029a749f1
GIT binary patch
literal 250786
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 |