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 0000000..60d05ef Binary files /dev/null and b/htdocs/favicon.ico differ diff --git a/htdocs/img/blad.jpg b/htdocs/img/blad.jpg new file mode 100644 index 0000000..ab9ff39 Binary files /dev/null and b/htdocs/img/blad.jpg differ diff --git a/htdocs/img/car.png b/htdocs/img/car.png new file mode 100644 index 0000000..b9c643f Binary files /dev/null and b/htdocs/img/car.png differ diff --git a/htdocs/img/me.jpg b/htdocs/img/me.jpg new file mode 100644 index 0000000..479f1b7 Binary files /dev/null and b/htdocs/img/me.jpg differ diff --git a/htdocs/index.php b/htdocs/index.php new file mode 100644 index 0000000..ee20c0b --- /dev/null +++ b/htdocs/index.php @@ -0,0 +1,31 @@ +setShared("app", $app); +$app->setDI($di); + +// Include user defined routes using $app-style. +foreach (glob(__DIR__ . "/../src/route/*.php") as $filename) { + require $filename; +} + +// Leave to router to match incoming request to routes +$app->router->handle( + $app->request->getRoute(), + $app->request->getMethod() +); diff --git a/htdocs/js/main.js b/htdocs/js/main.js new file mode 100644 index 0000000..7863fdd --- /dev/null +++ b/htdocs/js/main.js @@ -0,0 +1,8 @@ +/** + * To show off JS works and can be integrated. + */ +(function() { + "use strict"; + + console.info("main.js ready and loaded."); +})(); diff --git a/src/Page/DebugController.php b/src/Page/DebugController.php new file mode 100644 index 0000000..496ea9e --- /dev/null +++ b/src/Page/DebugController.php @@ -0,0 +1,44 @@ +di->get("view")->add("debug/oophp/info"); + $this->di->get("page")->render([ + "title" => "Details on loaded items", + ]); + } + + + + /** + * Render a page displaying details on how to debug a view. + * + * @return void + */ + public function view() + { + $this->di->get("view")->add("debug/oophp/view"); + $this->di->get("page")->render([ + "title" => "Info", + ]); + } +} diff --git a/src/Page/ErrorController.php b/src/Page/ErrorController.php new file mode 100644 index 0000000..9213bcc --- /dev/null +++ b/src/Page/ErrorController.php @@ -0,0 +1,87 @@ +di->get("view")->add($template, [ + "title" => $title, + "message" => $message, + ]); + $this->di->get("page")->render(["title" => $title], $status); + } + + + + /** + * Render a 403 forbidden page using the default page renderer. + * + * @return void + */ + public function page403() + { + $this->errorPage( + 403, + "403 Forbidden", + "You are not permitted to do this.", + "http_status/403" + ); + } + + + + /** + * Render a 404 Page not found using the default page renderer. + * + * @return void + */ + public function page404() + { + $this->errorPage( + 404, + "404 Page not found", + "The page you are looking for is not here.", + "http_status/404" + ); + } + + + + /** + * Render a 500 Page not found using the default page renderer. + * + * @return void + */ + public function page500() + { + $this->errorPage( + 500, + "500 Internal Server Error", + "An unexpected condition was encountered.", + "http_status/500" + ); + } +} diff --git a/src/Page/FlatFileContentController.php b/src/Page/FlatFileContentController.php new file mode 100644 index 0000000..d7198d1 --- /dev/null +++ b/src/Page/FlatFileContentController.php @@ -0,0 +1,57 @@ +di->get("request")->getRoute(); + $file1 = ANAX_INSTALL_PATH . "/content/" . $path . ".md"; + $file2 = ANAX_INSTALL_PATH . "/content/" . $path . "/index.md"; + + $file = is_file($file1) ? $file1 : null; + $file = is_file($file2) ? $file2 : $file; + + if (!$file) { + return; + } + + // Check that file is really in the right place + $real = realpath($file); + $base = realpath(ANAX_INSTALL_PATH . "/content/"); + if (strncmp($base, $real, strlen($base))) { + return; + } + + // Get content from markdown file + $content = file_get_contents($file); + $content = $this->di->get("textfilter")->parse( + $content, + ["yamlfrontmatter", "shortcode", "markdown", "titlefromheader"] + ); + + // Render a standard page using layout + $this->di->get("view")->add("default1/article", [ + "content" => $content->text, + "frontmatter" => $content->frontmatter, + ]); + $this->di->get("page")->render($content->frontmatter); + } +} diff --git a/src/Page/Page.php b/src/Page/Page.php new file mode 100644 index 0000000..6d5d2f2 --- /dev/null +++ b/src/Page/Page.php @@ -0,0 +1,51 @@ +di->get("view"); + + // Add static assets + $data["favicon"] = "favicon.ico"; + $data["stylesheets"] = ["css/style.css"]; + $data["javascripts"] = ["js/main.js"]; + + // Add views for common header, navbar and footer + $view->add("header/oophp/default", $data, "header"); + $view->add("navbar/oophp/default", $data, "navbar"); + $view->add("footer/oophp/default", $data, "footer"); + + // Add view for the overall layout, use region "layout" + $view->add("layout/oophp/default", $data, "layout"); + + // Render all views, using the region "layout", + // add to response and send. + $body = $view->renderBuffered("layout"); + $this->di->get("response")->setBody($body)->send($status); + exit; + } +} diff --git a/src/route/app.php b/src/route/app.php new file mode 100644 index 0000000..c3aa336 --- /dev/null +++ b/src/route/app.php @@ -0,0 +1,32 @@ +router->get("lek/hello-world", function () use ($app) { + echo "Hello World"; + return true; +}); + + + +/** +* Showing message Hello World, rendered within the page layout. + */ +$app->router->get("lek/hello-world-wrap", function () use ($app) { + $data = [ + "title" => "Show hello world within page layout | oophp", + "class" => "hello-world", + "content" => "Hello World", + ]; + + $app->view->add("content/oophp/default", $data); + + $app->page->render($data); +}); diff --git a/view/content/oophp/default.php b/view/content/oophp/default.php new file mode 100644 index 0000000..a24209c --- /dev/null +++ b/view/content/oophp/default.php @@ -0,0 +1,18 @@ +
+ +
diff --git a/view/debug/oophp/info.php b/view/debug/oophp/info.php new file mode 100644 index 0000000..0573fd2 --- /dev/null +++ b/view/debug/oophp/info.php @@ -0,0 +1,45 @@ +get("router"); + +$services = $di->getServices(); +$activeServices = $di->getActiveServices(); + + + +?>

Anax info

+ +

These are resources loaded in Anax.

+ + +

Routes loaded

+ +

The following routes are loaded:

+ + +getAll() as $route) : ?> + + + + + + +
PathMethodDescription
"getRule() ?>"getRequestMethod() ?>getInfo() ?>
+ +

The following internal routes are loaded:

+ + + + +

DI and services

+ +

These services are loaded into DI and bold are currently activated. +

diff --git a/view/debug/oophp/view.php b/view/debug/oophp/view.php new file mode 100644 index 0000000..462aa9e --- /dev/null +++ b/view/debug/oophp/view.php @@ -0,0 +1,23 @@ +

View development details

+ +

When working with a view you can access variables that are sent to the view from the route handler, or from the frontmatter. You will also have helper functions available. You can view all these by calling the following function.

+ +
+// Show incoming variables and view helper functions
+echo showEnvironment(get_defined_vars(), get_defined_functions());
+
+ +

The output will look something like this and may be useful for debugging and development.

+ + + +FOOTER + diff --git a/view/header/oophp/default.php b/view/header/oophp/default.php new file mode 100644 index 0000000..0e2c595 --- /dev/null +++ b/view/header/oophp/default.php @@ -0,0 +1,16 @@ + + +" alt="Logo"> + +HEADER diff --git a/view/http_status/403.php b/view/http_status/403.php new file mode 100644 index 0000000..9284622 --- /dev/null +++ b/view/http_status/403.php @@ -0,0 +1,20 @@ +
+

+

+
diff --git a/view/http_status/404.php b/view/http_status/404.php new file mode 100644 index 0000000..9284622 --- /dev/null +++ b/view/http_status/404.php @@ -0,0 +1,20 @@ +
+

+

+
diff --git a/view/http_status/500.php b/view/http_status/500.php new file mode 100644 index 0000000..9284622 --- /dev/null +++ b/view/http_status/500.php @@ -0,0 +1,20 @@ +
+

+

+
diff --git a/view/http_status/default.php b/view/http_status/default.php new file mode 100644 index 0000000..9284622 --- /dev/null +++ b/view/http_status/default.php @@ -0,0 +1,20 @@ +
+

+

+
diff --git a/view/layout/oophp/default.php b/view/layout/oophp/default.php new file mode 100644 index 0000000..ad3d0fb --- /dev/null +++ b/view/layout/oophp/default.php @@ -0,0 +1,87 @@ + + + + + <?= $title ?? "No title" ?> + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + diff --git a/view/navbar/oophp/default.php b/view/navbar/oophp/default.php new file mode 100644 index 0000000..099645f --- /dev/null +++ b/view/navbar/oophp/default.php @@ -0,0 +1,22 @@ + + +NAVBAR
+ + + ">Hem | + ">Redovisning | + ">Om | + ">Lek | + ">Debug +