markdown [Vagrant] Fedora #linux上的Vagrant和Virtualbox安装

[Vagrant] Fedora #linux上的Vagrant和Virtualbox安装

vagrant.md
# Vagrant and Virtualbox Installation on Fedora
This article explains how to install Vagrant and Virtualbox on Fedora 23/24 so you can build your development environments.
Vagrant and Virtualbox provide an easy way to create, configure and distribute development environments.

This play is also working on the brand new Fedora 26 with just a glitch about few missing headers files, see my note at the end.

VirtualBox Installation
Add VirtualBox repository and update your system:

```
$ sudo su -
# cd /etc/yum.repos.d/
# wget http://download.virtualbox.org/virtualbox/rpm/fedora/virtualbox.repo
# dnf update
```
Ensure that you are running latest installed kernel version, you can check it by comparing the output of following commands, version numbers should match:

```
# rpm -qa kernel |sort -V |tail -n 1
# uname -r
```
If you got a kernel update then reboot your system.

Install VirtualBox dependencies:

```
# dnf install binutils gcc make patch libgomp glibc-headers \
  glibc-devel kernel-headers kernel-devel dkms
```
`# dnf install VirtualBox`
Last command will build needed kernel modules, in case you need in the future to rebuild them, you can use the following command:
```# /usr/lib/virtualbox/vboxdrv.sh setup
```
In order to use VirtualBox, a user must be member of vboxusers group which was created automatically during Virtualbox installation. Add your username to vboxusers group

`# usermod -a -G vboxusers username`

## Vagrant Installation
Run the following commands to install Vagrant:

`$ sudo dnf install vagrant` 

Note that Fedora use libvirt as default provider, so to use Virtualbox instead you need to set an environment variable for it. Run the following commands:
```
$ echo "export VAGRANT_DEFAULT_PROVIDER=virtualbox" >> ~/.bashrc
If you prefer to use Vagrant with KVM, make sure to install libvirt packages for it.
```
`$ sudo dnf install -y vagrant vagrant-libvirt libvirt-devel`
Finally, install some useful vagrant plugins, but before we need to install .

```
$ vagrant plugin install vagrant-cachier
$ vagrant plugin install vagrant-hostmanager
```

While installing vagrant-cachier on a brand new Fedora 24 I had some errors about missing headers, to fix it you need to install the following packages:

`$ sudo dnf install ruby-devel redhat-rpm-config zlib-devel`
You can find more info about Gems installation in the Fedora Developer site.

Launch a Vagrant box
Now you can launch a vagrant box, for example try the official CentOS 7.

```
$ vagrant init centos/7
$ vagrant up --provider virtualbox
```
if you use libvirt provider:

`$ vagrant up --provider libvirt`


## What to do after a kernel update 

## launch the following command
> /usr/lib/virtualbox/vboxdrv.sh setup

## Add a second user
```
Vagrant.configure("2") do |config|
  if VAGRANT_COMMAND == "ssh"
      config.ssh.username = 'other_username'
  end
```

markdown [Redis]同一台服务器上的多个Redis实例#linux

[Redis]同一台服务器上的多个Redis实例#linux

redis.md
## FOR MULTIPLE REDIS INSTANCE INSTALLATION ON RHEL7+ USE THE FOLLOWING PATHS AND SETUP PROCESS:
* create a new redis .conf file

```Bash
$ cp /etc/redis.conf /etc/redis-xxx.conf
```

* edit /etc/redis-xxx.conf, illustrated as below

```Bash
...
#modify pidfile
#pidfile /var/run/redis/redis.pid
pidfile /var/run/redis/redis-xxx.pid

...
#dir /var/lib/redis/
dir /var/lib/redis-xxx/

...
#modify port
#port 6379
port 6380

...
#modify logfile
#logfile /var/log/redis/redis.log
logfile /var/log/redis/redis-xxx.log

...
#modify vm-swap-file
#vm-swap-file /tmp/redis.swap
vm-swap-file /tmp/redis-xxx.swap
...
```
* make dir /var/lib/redis-xxx

```Bash
$ mkdir -p /var/lib/redis-xxx
```

* THERE IS NO init.d files RHEL uses systemctl instead so:
* copy existing service over to your new service

```Bash
$ cp /usr/lib/systemd/system/redis.service /usr/lib/systemd/system/redis-xxx.service
```

* modify your new service script to the following: (just change the redis-xxx path)

```Bash
...

#[Unit]
Description=Redis persistent key-value database
After=network.target

#[Service]
ExecStart=/usr/bin/redis-server /etc/redis-xxx.conf --daemonize no
ExecStop=/usr/bin/redis-shutdown
User=redis
Group=redis

#[Install]
WantedBy=multi-user.target
...
```

* if you have sentinel enabled on your system you will need to: (otherwise skip this step)

```Bash
# Copy values from cat /usr/lib/systemd/system/redis.service to /usr/lib/systemd/system/redis-xxx.service
$ cp /usr/lib/systemd/system/redis.service /usr/lib/systemd/system/redis-xxx.service
```

* then edit the contents of /usr/lib/systemd/system/redis-xxx.service (just change the /etc/redis-xxx path again)


* start the new services:

```Bash
$ service redis-xxx start
```

* check the new services status:

```Bash
$ service redis-xxx status
```


* stop the new services status:

```Bash
$ service redis-xxx stop
```


* restart the new services status:

```Bash
$ service redis-xxx restart
```

* if you get some problems with service not found:
* you can do the following:
```Bash
$ systemctl unmask packagekit.service
$ systemctl mask packagekit.service
```
* then try to start the service again

markdown XPath几点提示

xpath
#### in this case after `<some-component>` html element is lot of tags inbetween.  We skip them by `//li` and search only `<li>` that has a given string `//some-component//li`. For some tags (`span`, `a`, `button`) has direct `text()` working but for `<li>` `text()` returns `undefined`. Two solutions in b) and c)
a) `//some-component/li/span[text() = "' + name + '"];`

b) `//some-component/li[text()[contains(.,"'+ name +'")]];`

c) `//some-component/li[contains(., "'+ name +'")];`

#### if there is more nesting below `<li>` to get text from last `<li>` element we can use:
`//some-component//li[text()[contains(text(), "' + name '")]];`

#### remove unnecesary space in `span`, `a` text element
`//td[@class='score-time status']/a[normalize-space() = '16 : 00']`

#### other search by input value
`//button[@value='press me']`

#### other search by class name
`//div[contains(@class, "' + name + '")];`

#### find parent of element
a) `//div/span[contains(text(), 'XYZ')]/..  //div`

b) `//div/span/li/a/ancestor::div`  //more specific

#### find by comments in html with string
`//ul/li/comment()[contains(., 'item in $select.items')]`

#### get div with attribute
`//div/@some-attribute-name` //cannot select more elements after this selection

`//div[@some-attribute-name="value"]//h3/span`

#### select next `div` sibling
`//div[text() = ' Color Digest ']/following-sibling::div`

#### select given element from list
`//ol[contains(@id, "autocomplete-view")][1]` - usually works but if cannot find another than first element use:

`(//ol[contains(@id, "autocomplete-view")])[1]`

markdown 角度命令

Angular-CLI.md
https://github.com/angular/angular-cli/wiki/


## Install Angular CLI 
- use *sudo* if you get a permission error. 
- Like NPM, this installs the latest Angular CLI as a global node plugin to */usr/local/lib/node_modules/@angular/*.
- `g` flag stands for *generate*.

> npm install -g @angular/cli


## Create an hello-world application
> cd /users/sarpay/documents

> mkdir wwwhost

> cd wwwhost

> ng new hello-world

| Trailing Command | Description |
|--|--|
| -routing | Generates a routing module. |
| -style | The file extension to be used for style files. |
| -d | Run through without making any changes. |
| -f | Adds more details to output logging. |
| -v | Adds more details to output logging. |
| --view-encapsulation | Specifies the view encapsulation strategy. |
| -p | The prefix to apply to generated selectors. |
| -s | Specifies if the style will be in the ts file. |
| -t | Specifies if the template will be in the ts file. |
| -c | Specifies the change detection strategy. |
| -S | Skip creating spec files. |         
| --skip-package-json | Do not add dependencies to package.json. |


## Install Angular Material
> cd hello-world

> ng add @angular/material


## Run the application
> cd hello-world
> ng serve -o

| Trailing Command | Description |
|--|--|
| -o | auto opens app in browser |

----


ng generate component [name]                      create a new component

    -d                                            Run through without making any changes.
    -f                                            Forces overwriting of files.
    -m                                            Allows specification of the declaring module.
    --selector                                    The selector to use for the component.
    -p                                            The prefix to apply to generated selectors.
    --project                                     The name of the project
    -s                                            Specifies if the style will be in the ts file.
    -t                                            Specifies if the template will be in the ts file.
    -c                                            Specifies the change detection strategy.
    --styleext                                    The file extension to be used for style files.
    --spec                                        Specifies if a spec file is generated.
    --flat                                        Flag to indicate if a dir is created.
    --skip-import                                 Flag to skip the module import.
    --export                                      Specifies if declaring module exports the component.


ng generate service [name]                        create a new component
    
    
ng generate class [name]                          create a new class

    -d                                            Run through without making any changes.
    -f                                            Forces overwriting of files.
    --project                                     The name of the project.
    --spec                                        Specifies if a spec file is generated.
    --type                                        Specifies if a spec file is generated.
    
    
ng generate directive


ng generate enum


ng generate guard


ng generate interace


ng generate module


ng generate pipe


ng generate application


ng generate library


ng generate universal


## Update Angular

In order to update the angular-cli package installed globally in your system, you need to run:

    npm uninstall -g angular-cli
    npm cache clean or npm cache verify (if npm 5)
    npm install -g @angular/cli@latest

Depending on your system, you may need to prefix the above commands with `sudo`.

Also, most likely you want to also update your local project version, because inside your project directory it will be selected with higher priority than the global one:

    rm -rf node_modules
    npm uninstall --save-dev angular-cli
    npm install --save-dev @angular/cli@latest
    npm install

thanks _grizzm0_ for pointing this out on [GitHub](https://github.com/angular/angular-cli/issues/4391#issuecomment-277199786).

After updating your CLI, you probably want to [update your Angular version](https://update.angular.io/) too.

markdown Sqlite,auto_increase

Sqlite,auto_increase

Set Number Of Auto Increase.md
# Set Auto Increase Num
There is a build-in table called sqlite_sequence store the current index of auto increase number of table.
``` SQL
sqlite> select * from sqlite_sequence;
name       seq
---------  --------------------
CASE_INFO  1284
COMMIT_TR  0
SVN_FILES  2774
```
reset this to 0, and when insert record to table, number will change.

markdown 如何在不获取nohup.out的情况下使用nohup命令?

https://stackoverflow.com/questions/10408816/how-do-i-use-the-nohup-command-without-getting-nohup-out

nohup-without-out.md

nohup only writes to nohup.out if the output is otherwise to the terminal. If you redirect the output of the command somewhere else - including /dev/null - that's where it goes instead.
```
# doesn't create nohup.out
nohup command >/dev/null 2>&1
```

If you're using nohup, that probably means you want to run the command in the background by putting another & on the end of the whole thing:
```
# runs in background, still doesn't create nohup.out
nohup command >/dev/null 2>&1 &
```

On Linux, running a job with nohup automatically closes its input as well. On other systems, notably BSD and OS X, that is not the case, so when running in the background, you might want to close its input manually. While closing input has no effect on the creation or not of nohup.out, it avoids another problem: if a background process tries to read anything from standard input, it will pause, waiting for you to bring it back to the foreground and type something. So the extra-safe version looks like this:
```
# completely detached from terminal 
nohup command </dev/null >/dev/null 2>&1 &
```
Note, however, that this does not prevent the command from accessing the terminal directly, nor does it remove it from your shell's process group. If you want to do the latter, you can do so by running disown with no argument as the next command, at which point the process is no longer associated with a shell "job" and will not have any signals (not just HUP) forwarded to it from the shell.

markdown 디버그출력(보고서매크로)

#cpp #string

rpt.md
# win32 에서의 디버그 출력
crtdbg.h 에 정의된 `_RPTn`과 `_RPTFn` 매크로를 이용하여 printf 형식의 문자열을
디버그 시 출력할 수 있다.

## `_RPTn`
_RPT1 부터 _RPT4 매크로는 해당 갯수만큼 파라미터를 사용한다.

```cpp
_RPT0(_CRT_WARN, "문자열");
```

## `_RPTFn`
_RPTn과 같지만 해당 매크로가 있는 파일 이름과 줄 번호도 출력한다.

markdown [昨天我学会了......]继续学习#general

[昨天我学会了......]继续学习#general

empty_local_branch.md
# How to create an empty stand-alone branch in GIT
----------
I’m trying to refactor a web app over to Laravel. Initially, I checked out the code from GIT, created a branch, and started making my changes. When I realized how drastic the changes were, I decided that it would be better to start with a blank slate.

I deleted everything in the branch and started from scratch, but the obvious problem is that the branch shares commit history with the master branch.

After doing some research, I came across a git command to create an “orphan” branch that doesn’t share any commit history with ‘master’. Perfect for maintaining different projects in the same repository without mixing up their commit histories. Here’s how to do it:

Before starting, upgrade to the latest version of GIT. To make sure you’re running the latest version, run

```
which git
```
If it spits out an old version, you may need to augment your PATH with the folder containing the version you just installed. 

Ok, we’re ready. After doing a cd into the folder containing your git checkout, create an orphan branch. For this example, I’ll name the branch “mybranch.”
```
git checkout --orphan mybranch
```
Delete everything in the orphan branch
```
git rm -rf .
```
Make some changes
```
vi README.txt
```
Add and commit the changes
```
git add README.txt
git commit -m "Adding readme file"
```
That’s it. If you run
```
git log
```
you’ll notice that the commit history starts from scratch. To switch back to your master branch, just run
```
git checkout master
```
. You can return to the orphan branch by running
```
git checkout mybranch
#git
```
01_git_alias.md
# Git Tips and tricks
--------
### Git cli guides
```sh
thieryl@thieryl[12:42:19]: $ git help -g 
The common Git guides are:

   attributes   Defining attributes per path
   everyday     Everyday Git With 20 Commands Or So
   glossary     A Git glossary
   ignore       Specifies intentionally untracked files to ignore
   modules      Defining submodule properties
   revisions    Specifying revisions and ranges for Git
   tutorial     A tutorial introduction to Git (for version 1.5.1 or newer)
   workflows    An overview of recommended workflows with Git

'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
```

### Git Aliases
```sh
git config --global alias.<handle> <command> 
git config --global alias.st status
```

### list you git configuration
```bash 
thieryl@thieryl[09:52:44]: $ git config --list 
user.email=thiery.louison@redboxdigital.com
user.name=thiery louison
alias.aa=add --all
alias.bv=branch -vv
alias.ba=branch -ra
alias.bd=branch -d
alias.ca=commit --amend
alias.cb=checkout -b
alias.cm=commit -a --amend -C HEAD
alias.cam=commit -am
alias.ci=commit -a -v
alias.co=checkout
alias.di=diff
alias.ll=log --pretty=format:%C(yellow)%h%Cred%d\ %Creset%s%Cblue\ [%cn] --decorate --numstat
alias.ld=log --pretty=format:%C(yellow)%h\ %C(green)%ad%Cred%d\ %Creset%s%Cblue\ [%cn] --decorate --date=short --graph
alias.ls=log --pretty=format:%C(green)%h\ %C(yellow)[%ad]%Cred%d\ %Creset%s%Cblue\ [%cn] --decorate --date=relative
alias.mm=merge --no-ff
alias.st=status --short --branch
alias.tg=tag -a
alias.pu=push --tags
alias.un=reset --hard HEAD
alias.uh=reset --hard HEAD^
color.ui=auto
```
### Get git bash completion
```sh
curl http://git.io/vfhol > ~/.git-completion.bash && echo '[ -f ~/.git-completion.bash ] && . ~/.git-completion.bash' >> ~/.bashrc

```

### List of the remote branches
To see all the branches, try the following command:

```sh
thieryl@thieryl[09:50:31]: $ git branch -a 
  master
* my_newfeature
  remotes/origin/master
  remotes/tlo/master
[~/.dotfiles]
```

### Tracking remote branch and creating local branch with the same name.
```sh
git checkout -t origin/{{branch_name}}
```

### Remember the branch structure after a local merge
```sh
git merge --no-ff some-branch-name
```

### Modify previous commit without modifying the commit message
```sh
git add --all && git commit --amend --no-edit
```

### Add a local branch tracking the remote branch.
```bash
$ git branch --track style origin/style
Branch style set up to track remote branch style from origin.
$ git branch -a
  style
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/style
  remotes/origin/master
$ git hist --max-count=2
* 2faa4ea 2011-03-09 | Changed README in original repo (HEAD, origin/master, origin/HEAD, master) [Thiery Louison]
* 6e6c76a 2011-03-09 | Updated index.html (origin/style, style) [Thiery Louison]
```

### Map a local branch tracking to a remote branch
```bash 
thieryl@thieryl[09:47:38]: $ git checkout -b my_newfeature -t tlo/master
thieryl@thieryl[09:50:23]: $ git status -v 
On branch my_newfeature
Your branch is up to date with 'tlo/master'.

nothing to commit, working tree clean
[~/.dotfiles]
thieryl@thieryl[09:50:31]: $ 

thieryl@thieryl[09:48:43]: $ git ld
* e5480c7 2018-07-19 (HEAD -> my_newfeature, tlo/master, origin/master, master) Add new git alias [thiery louison]
* 508b1b4 2018-07-19 Add .gitconfig file to repo [thiery louison]
* 33ac493 2018-07-04 Add new functions [thiery louison]
* c0026b1 2018-07-02 Add new aliases and new variables [thiery louison]
*   210c4ed 2018-06-08 Merge branch 'master' of github.com:thieryl/dotfiles [thiery louison]
|\  
| * 9598e8c 2018-05-23 Delete .bashrc_old [GitHub]
| * ab974f7 2018-05-23 Update .bashrc_old [GitHub]
* | d832d62 2018-06-08 Add new aliases [thiery louison]
|/  
* 8a2acd3 2018-05-23 Add .bash_promt [thiery louison]
* c4fc360 2018-05-23 Add new alias [thiery louison]
* 2d1d74c 2017-09-25 Modified some functionality [thiery louison]
* 9ba5d65 2017-09-12 Add the password generator pgen to the .bash_aliases file [thiery louison]
* 1cf2a81 2017-08-31 Add new alias for git [thiery louison]
* 8033abc 2017-08-31 Add new alias and new functions [thiery louison]
* 43ba75d 2017-08-31 Initial commit [thiery louison]

```

markdown 创建您的第一个Slim框架应用程序

创建您的第一个Slim框架应用程序

slim-app-tutorial.md
# Creating your first Slim Framework Application

The Slim Framework is a great micro frameworks for Web application, RESTful API's and Websites. 
This Tutorial shows how to create a very basic but flexible project for every use case.

## Table of contents

* [Requirements](#requirements)
* [Introduction](#introduction)
* [Installation](#installation)
* [Directory structure](#directory-structure)
* [Front controller](#front-controller)
* [Bootstrap](#bootstrap)
* [Container](#container)
* [Middleware](#middleware)
* [Routes](#routes)
* [Configuration](#configuration)
* [Composer](#composer)
* [Starting](#starting)
* [Errors and Logging](#errors-and-logging)
* [Views and Templates](#views-and-templates)
* [Database](#database)
* [Deployment](#deployment)

## Requirements

* PHP 7.x
* MySQL 5.7+
* [Apache](https://gist.github.com/odan/dcf6c3155899677ee88a4f7db5aac284#install-apache-php-mysql)
* Apache [mod_rewrite](https://gist.github.com/odan/dcf6c3155899677ee88a4f7db5aac284#enable-apache-mod_rewrite) module
* [Composer](https://gist.github.com/odan/dcf6c3155899677ee88a4f7db5aac284#install-composer)

## Introduction

I'm sure you've read the official Slim tutorial "[First Application Walkthrough](https://www.slimframework.com/docs/tutorial/first-app.html)" and found that it doesn't work as expected on your server. Most of the people I spoke to on StackOverflow and in the Slim Forum had similar problems due to this tutorial.

I think this tutorial should follow good practices and the directory structure of [Slim-Skeleton](https://github.com/slimphp/Slim-Skeleton). The current version of the official tutorial is "outdated" because it does not reflect the best practices of the PHP community and makes it very difficult, especially for beginners.

This tutorial tries to make the start easier and less confusing.

## Installation

Composer is the best way to install Slim Framework. Open the console and change to the project root directory. Then enter:

```bash
composer require slim/slim
```

This creates a new folder `vendor/` and the files `composer.json` + `composer.lock` with all the dependencies of your application.

Please don't commit the `vendor/` to your git repository. To set up the git repository correctly, create a file called `.gitignore` in the project root folder and add the following lines to this file:

```
vendor/
.idea/
```

## Directory structure

A good directory structure helps you organize your code, simplifies setup on the web server and increases the security of the entire application.

Create the following directory structure in the root directory of your project:

```
.
├── config/             Configuration files
├── public/             Web server files (DocumentRoot)
│   └── .htaccess       Apache redirect rules for the front controller
│   └── index.php       The front controller
├── templates/          Twig templates
├── src/                PHP source code (The App namespace)
├── tmp/                Temporary files (cache and logfiles)
├── vendor/             Reserved for composer
├── .htaccess           Internal redirect to the public/ directory
└── .gitignore          Git ignore rules
```

In a web application, it is important to distinguish between the public and non-public areas.

The folder `public` serves your application and will therefore also be directly accessible by all browsers, search engines and API clients. All other folders are not public and must not be accessible online. This can be done by defining the `public` folder in Apache as `DocumentRoot` of your website. But more about that later.

## Front controller

The [front controller](https://en.wikipedia.org/wiki/Front_controller) is the entry point to your slim application and handles all requests by channeling requests through a single handler object.

The content of  `public/.htaccess`:

```htaccess
# Redirect to front controller
RewriteEngine On
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L] 
```

### Internal redirect to the front controller

The `.htaccess` file in the project root is required in at least two cases.

* For the development environment

For example, if you are developing with XAMPP, you have only one host and several subdirectories. So that Slim runs in this environment without additional setup, this file was created. This simplifies the entire development environment, as you can easily manage any number of applications at the same time.

* In case your application is deployed within subfolders of the vhost. (I've seen that many times before).

The content of `.htaccess`:

```htaccess
RewriteEngine on
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
```

## Bootstrap

Add the following code to the front controller file `public/index.php`.

```php
<?php

/** @var Slim\App $app */
$app = require __DIR__ . '/../config/bootstrap.php';

// Start
$app->run();

```

The entire configuration of your application is stored and managed in the `config` folder. 

Create the following config files with all settings, routings, middleware etc.

Content of file `config/bootstrap.php`

```php
<?php

require_once __DIR__ . '/../vendor/autoload.php';

// Instantiate the app
$app = new \Slim\App(['settings' => require __DIR__ . '/../config/settings.php']);

// Set up dependencies
require  __DIR__ . '/container.php';

// Register middleware
require __DIR__ . '/middleware.php';

// Register routes
require __DIR__ . '/routes.php';

return $app;

```

## Container

Slim uses a dependency container to prepare, manage, and inject application dependencies. 
Slim supports containers that implement PSR-11 or the Container-Interop interface.

The container configuration is an importand part of a good application setup.

Content of file `config/container.php`

```php
<?php

use Slim\Container;

/** @var \Slim\App $app */
$container = $app->getContainer();

// Activating routes in a subfolder
$container['environment'] = function () {
    $scriptName = $_SERVER['SCRIPT_NAME'];
    $_SERVER['SCRIPT_NAME'] = dirname(dirname($scriptName)) . '/' . basename($scriptName);
    return new Slim\Http\Environment($_SERVER);
};
```

## Middleware

Content of file `config/middleware.php`.

At the moment this file contains no middleware.

```php
<?php

// Slim middleware


```

## Routes

Content of file `config/routes.php`

```php
<?php

use Slim\Http\Request;
use Slim\Http\Response;

$app->get('/', function (Request $request, Response $response) {
    $response->getBody()->write("It works! This is the default welcome page.");

    return $response;
})->setName('root');

$app->get('/hello/{name}', function (Request $request, Response $response) {
    $name = $request->getAttribute('name');
    $response->getBody()->write("Hello, $name");

    return $response;
});
```

## Configuration

Content of file `config/settings.php`

```php
<?php

$settings = [];

// Slim settings
$settings['displayErrorDetails'] = true;
$settings['determineRouteBeforeAppMiddleware'] = true;

// Path settings
$settings['root'] = dirname(__DIR__);
$settings['temp'] = $settings['root'] . '/tmp';
$settings['public'] = $settings['root'] . '/public';

// View settings
$settings['twig'] = [
    'path' => $settings['root'] . '/templates',
    'cache_enabled' => false,
    'cache_path' =>  $settings['temp'] . '/twig-cache'
];

// Database settings
$settings['db']['host'] = 'localhost';
$settings['db']['username'] = 'root';
$settings['db']['password'] = '';
$settings['db']['database'] = 'test';
$settings['db']['charset'] = 'utf8';
$settings['db']['collation'] = 'utf8_unicode_ci';

return $settings;
```

## Composer

By convention all application specific PHP classes are stored in the `src` folder. We create the namespace `App` and use the `src` folder as a starting point for composer:

Content of `composer.json`

```json
{
  "require": {
    "php": "^7.0",
    "slim/slim": "^3.9"
  },
  "autoload": {
    "psr-4": {
      "App\\": "src"
    }
  },
  "autoload-dev": {
    "psr-4": {
      "App\\Test\\": "tests"
    }
  },
  "config": {
    "sort-packages": true
  }
}
```

Run `composer update` so that the changes take effect.

## Starting

Now open the browser and navigate to the slim application:

* http://localhost/

If you are running the web app within a subdirectory just add the name of the subdirectory to the url.

* http://localhost/{my-project-name}/

You should see the message: `It works! This is the default welcome page.`

Then open http://localhost/hello/world or http://localhost/{my-project-name}/hello/world

You should see the message: `Hello, world`

## Views and Templates

The [Twig View](https://github.com/slimphp/Twig-View) is a Slim Framework view helper built on top of the [Twig](https://twig.symfony.com/) templating component. You can use this component to create and render templates in your Slim Framework application.

### Twig installation

Run composer

```bash
composer require slim/twig-view
```

Add this code to the file: `config/container.php`

```php
// Register Twig View helper
$container['view'] = function (Container $container) {
    $settings = $container->get('settings');
    $viewPath = $settings['twig']['path'];

    $twig = new \Slim\Views\Twig($viewPath, [
        'cache' => $settings['twig']['cache_enabled'] ? $settings['twig']['cache_path'] : false
    ]);

    /** @var Twig_Loader_Filesystem $loader */
    $loader = $twig->getLoader();
    $loader->addPath($settings['public'], 'public');

    // Instantiate and add Slim specific extension
    $router = $container->get('router');
    $uri = \Slim\Http\Uri::createFromEnvironment($container->get('environment'));
    $twig->addExtension(new \Slim\Views\TwigExtension($router, $uri));

    return $twig;
};
```

### Twig templates

Add a new template: `templates/time.twig`

```twig
<!DOCTYPE html>
<html>
<head>
    <base href="{{ base_url() }}/"/>
</head>
<body>
Current time: {{ now }}
</body>
</html>

```

Add a new route in `config/routes.php`

```php
$app->get('/time', function (Request $request, Response $response) {
    $viewData = [
        'now' => date('Y-m-d H:i:s')
    ];

    return $this->get('view')->render($response, 'time.twig', $viewData);
});
```

Then open http://localhost/time or http://localhost/{my-project-name}/time

You should see the message: `Current time: 2017-12-06 21:52:57`

## Errors and Logging

### Display Error Details

What can I do with a 500 Internal Server Error?

That's probably happened to all of us before: You open your website and find only a more or less meaningful page that reports a "Code 500 - Internal Server Error". But what does that mean?

This is a very general message from the server that an error has occurred, which is almost certainly due to the configuration of the server or the incorrect execution of a server script.

The default error handler can also include detailed error diagnostic information. To enable this you need to set the `displayErrorDetails` setting to `true`:

```php
$settings['displayErrorDetails'] = true;
```

### Logging of errors

It becomes more difficult if you have worked in the server configuration files. 
Tiny errors in the `.htaccess` file or the filesystem permissions can lead to such errors.

A quick checklist:

* Does your Apache `DocumentRoot` points to the `public` folder?
* Did you set the write permissions to the `temp` and `upload` folder correctly?
* Are the database connection parameters correct?

To see where the problem is, you should log all errors in a logfile. Here you can find instructions:

[Logging errors in Slim 3](https://akrabat.com/logging-errors-in-slim-3/)

### Logging

Installation

```
composer require monolog/monolog
```

Add this new settings in `config/settings.php`

```php
// Logger settings
$settings['logger'] = [
    'name' => 'app',
    'file' => $settings['temp'] . '/logs/app.log',
    'level' => \Monolog\Logger::ERROR,
];
```

Add a new logger entry in `config/container.php`

```php
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Psr\Log\LoggerInterface;

$container['logger'] = function (Container $container) {
    $settings = $container->get('settings');
    $logger = new Logger($settings['logger']['name']);
    
    $level = $settings['logger']['level'];
    if (!isset($level)) {
        $level = Logger::ERROR;
    }
    
    $logFile = $settings['logger']['file'];
    $handler = new RotatingFileHandler($logFile, 0, $level, true, 0775);
    $logger->pushHandler($handler);
    
    return $logger;
};
```

Add a new route in `config/routes.php`

```php
use Psr\Log\LoggerInterface;
use Slim\Container;

$app->get('/logger-test', function (Request $request, Response $response) {
    /** @var Container $this */
    /** @var LoggerInterface $logger */

    $logger = $this->get('logger');
    $logger->error('My error message!');

    $response->getBody()->write("Success");

    return $response;
});
```

Then open http://localhost/logger-test or http://localhost/{my-project-name}/logger-test

Check the content of the logfile in the project sub-directory: `tmp/logs/app-2018-04-24.log`

You should see the logged error message. Example: `[2018-04-24 21:12:47] app.ERROR: My error message! [] []`

## Database

### Database configuration

Adjust the necessary connection settings in the file `config/settings.php`.

### PDO

Add a container entry for the PDO connection:

```php
$container['pdo'] = function (Container $container) {
    $settings = $container->get('settings');
    
    $host = $settings['db']['host'];
    $dbname = $settings['db']['database'];
    $username = $settings['db']['username'];
    $password = $settings['db']['password'];
    $charset = $settings['db']['charset'];
    $collate = $settings['db']['collation'];
    
    $dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
    
    $options = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_PERSISTENT => false,
        PDO::ATTR_EMULATE_PREPARES => false,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES $charset COLLATE $collate"
    ];

    return new PDO($dsn, $username, $password, $options);
};
```

### Query Builder

For security reasons (SQL injections), SQL statements should no longer be written by yourself, but generated using a query builder. For this purpose, the PHP community offers already established and tested libraries. Here is a selection I can recommend:

* [Illuminate Database](https://github.com/illuminate/database)
* [CakePHP Database](https://github.com/cakephp/database)
* [odan/database](https://github.com/odan/database)

You should use a query builder only within a [Data Mapper](https://martinfowler.com/eaaCatalog/dataMapper.html) or Repository class.
Here you can find some examples of a Data Mapper class. [TicketMapper](https://github.com/slimphp/Tutorial-First-Application/blob/master/src/classes/TicketMapper.php), [ComponentMapper.php](https://github.com/slimphp/Tutorial-First-Application/blob/master/src/classes/ComponentMapper.php).

The Laravel [Illuminate Database query builder](https://laravel.com/docs/master/queries) brings a super natrual, fluent and smooth query builder to you. The only disadvantage is that you get a lot of global laravel functions and classes as dependencies on board. Caution: Laravel Illuminate does not return arrays, but collections with stdClass instances. You should get along with that, too.

**Installation**

```
composer require illuminate/database
```

Add a new container entry in the file: `config/container.php`

```php
use Illuminate\Database\Connectors\ConnectionFactory;
use Illuminate\Database\Connection;

$container['db'] = function (Container $container) {
    $settings = $container->get('settings');
    
    $config = [
        'driver' => 'mysql',
        'host' => $settings['db']['host'],
        'database' => $settings['db']['database'],
        'username' => $settings['db']['username'],
        'password' => $settings['db']['password'],
        'charset'  => $settings['db']['charset'],
        'collation' => $settings['db']['collation'],
    ];
    
    $factory = new ConnectionFactory(new \Illuminate\Container\Container());
    
    return $factory->make($config);
};

$container['pdo'] = function (Container $container) {
    return $container->get('db')->getPdo();
};
```

Generate and execute a query:

```php
use Illuminate\Database\Connection;

$app->get('/databases', function (Request $request, Response $response) {
    /** @var Container $this */
    /** @var Connection $db */
    
    $db = $this->get('db');

    // fetch all rows as collection
    $rows = $db->table('information_schema.schemata')->get();

    // return a json response
    return $response->withJson($rows);
});
```

You can build very complex sql queries. Here are just some CRUD examples:

```php
// Retrieving a single Row
$user = $this->db->table('users')->select('id', 'username', 'email')->where('id', '=', 1)->first();

// Retrieving all rows as stdClass
$users = $this->db->table('users')->select('id', 'username', 'email')->get();

// Retrieving all rows as array
$users = $this->db->table('users')->select('id', 'username', 'email')->get()->toArray();

// Insert a new row
$success = $this->db->table('users')->insert(['username' => 'max', 'email' => 'max@example.com']);

// Insert a new row and get the new ID (primary key)
$userId = $this->db->table('users')->insertGetId(['username' => 'sofia', 'email' => 'sofia@example.com']);

// Delete user with id = 1
$this->db->table('users')->delete(1);

// Delete all users where users.votes > 100
$this->db->table('users')->where('votes', '>', 100)->delete();
```

Here you can find the [documentation](https://laravel.com/docs/5.6/queries)
and a [Eloquent Cheat Sheet](http://laragems.com/post/eloquent-cheat-sheet).


## Deployment

For deployment on a productive server, there are some important settings and security releated things to consider.

You can use composer to generate an optimized build of your application. 
All dev-dependencies are removed and the Composer autoloader is optimized for performance. 

```
composer update --no-dev --optimized-autoloader
```

Furthermore, you should activate caching for Twig to increase the performance of the template engine. 

```php
$settings['twig']['cache_enabled'] = true;
```

Routing can also be accelerated by using a cache file:

```php
$settings['routerCacheFile'] = __DIR__ . '/../tmp/routes.cache.php',
```

Set the option `displayErrorDetails` to `false` in production:

```php
$settings['displayErrorDetails'] = false;
```

**Important**: For security reasons you MUST set the Apache `DocumentRoot` and the `<Directory` of the webhosting to the `public` folder. Otherwise, it may happen that someone else accesses the internal files from outside. [More details](https://www.digitalocean.com/community/tutorials/how-to-move-an-apache-web-root-to-a-new-location-on-ubuntu-16-04)

`/etc/apache2/sites-enabled/000-default.conf`

```htacess
DocumentRoot /var/www/example.com/htdocs/public
```

Tip: Never store secret passwords in a Git / SVN repository. 
Instead you could store them in a file like `env.php` and place this file one directory above your application directory. e.g.

```
/var/www/example.com/env.php
```

markdown 有用的Mac终端命令

有用的Mac终端命令

mac-terminal.md
## Kill Processes
* Bluetooth -- sudo killall blued
* Webcam -- sudo killall AppleCameraAssistant; sudo killall VDCAssistant
* Finder -- sudo killall Finder
* Sound -- sudo killall coreaudiod
* Fix Eternal Harddrive mounting issue -- sudo pkill -f fsck


## Find Application Serial Keys
Panic Coda -- defaults read com.panic.Coda2 SerialNumber

## Copy an entire Folder/Directory from a server
scp -r rkirkner@website.com:/path/to-stuff/you/want &nbsp;&nbsp;&nbsp; /Users/rkirkner/path/to-put/the-stuff/in/

## Copy SSH key to server
ssh-copy-id -i ~/.ssh/mykey user@host