yannstatic/static/2020/02/21/PhpMyAdmin.html

2210 lines
214 KiB
HTML
Raw Normal View History

2024-10-31 20:18:37 +01:00
<!DOCTYPE html><html lang="fr">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>PhpMyAdmin (gestionnaire bases mysql/mariadb) - YannStatic</title>
<meta name="description" content="PhpMyAdmin">
<link rel="canonical" href="https://static.rnmkcy.eu/2020/02/21/PhpMyAdmin.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
<!-- - include head/favicon.html - -->
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
<!-- end custom head snippets --><script>(function() {
window.isArray = function(val) {
return Object.prototype.toString.call(val) === '[object Array]';
};
window.isString = function(val) {
return typeof val === 'string';
};
window.hasEvent = function(event) {
return 'on'.concat(event) in window.document;
};
window.isOverallScroller = function(node) {
return node === document.documentElement || node === document.body || node === window;
};
window.isFormElement = function(node) {
var tagName = node.tagName;
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
};
window.pageLoad = (function () {
var loaded = false, cbs = [];
window.addEventListener('load', function () {
var i;
loaded = true;
if (cbs.length > 0) {
for (i = 0; i < cbs.length; i++) {
cbs[i]();
}
}
});
return {
then: function(cb) {
cb && (loaded ? cb() : (cbs.push(cb)));
}
};
})();
})();
(function() {
window.throttle = function(func, wait) {
var args, result, thisArg, timeoutId, lastCalled = 0;
function trailingCall() {
lastCalled = new Date;
timeoutId = null;
result = func.apply(thisArg, args);
}
return function() {
var now = new Date,
remaining = wait - (now - lastCalled);
args = arguments;
thisArg = this;
if (remaining <= 0) {
clearTimeout(timeoutId);
timeoutId = null;
lastCalled = now;
result = func.apply(thisArg, args);
} else if (!timeoutId) {
timeoutId = setTimeout(trailingCall, remaining);
}
return result;
};
};
})();
(function() {
var Set = (function() {
var add = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (data[i] === item) {
return;
}
}
this.size ++;
data.push(item);
return data;
};
var Set = function(data) {
this.size = 0;
this._data = [];
var i;
if (data.length > 0) {
for (i = 0; i < data.length; i++) {
add.call(this, data[i]);
}
}
};
Set.prototype.add = add;
Set.prototype.get = function(index) { return this._data[index]; };
Set.prototype.has = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (this.get(i) === item) {
return true;
}
}
return false;
};
Set.prototype.is = function(map) {
if (map._data.length !== this._data.length) { return false; }
var i, j, flag, tData = this._data, mData = map._data;
for (i = 0; i < tData.length; i++) {
for (flag = false, j = 0; j < mData.length; j++) {
if (tData[i] === mData[j]) {
flag = true;
break;
}
}
if (!flag) { return false; }
}
return true;
};
Set.prototype.values = function() {
return this._data;
};
return Set;
})();
window.Lazyload = (function(doc) {
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
var createNode = function(name, attrs) {
var node = doc.createElement(name), attr;
for (attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
node.setAttribute(attr, attrs[attr]);
}
}
return node;
};
var end = function(type, url) {
var s, q, qi, cbs, i, j, cur, val, flag;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
s[url] = true;
for (i = 0; i < q.length; i++) {
cur = q[i];
if (cur.urls.has(url)) {
qi = cur, val = qi.urls.values();
qi && (cbs = qi.callbacks);
for (flag = true, j = 0; j < val.length; j++) {
cur = val[j];
if (!s[cur]) {
flag = false;
}
}
if (flag && cbs && cbs.length > 0) {
for (j = 0; j < cbs.length; j++) {
cbs[j].call(context);
}
qi.load = true;
}
}
}
}
};
var load = function(type, urls, callback) {
var s, q, qi, node, i, cur,
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
for (i = 0; i < q.length; i++) {
cur = q[i];
if (_urls.is(cur.urls)) {
qi = cur;
break;
}
}
val = _urls.values();
if (qi) {
callback && (qi.load || qi.callbacks.push(callback));
callback && (qi.load && callback());
} else {
q.push({
urls: _urls,
callbacks: callback ? [callback] : [],
load: false
});
for (i = 0; i < val.length; i++) {
node = null, url = val[i];
if (s[url] === undefined) {
(type === 'js' ) && (node = createNode('script', { src: url }));
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
if (node) {
node.onload = (function(type, url) {
return function() {
end(type, url);
};
})(type, url);
(doc.head || doc.body).appendChild(node);
s[url] = false;
}
}
}
}
}
};
return {
js: function(url, callback) {
load('js', url, callback);
},
css: function(url, callback) {
load('css', url, callback);
}
};
})(this.document);
})();
</script><script>
(function() {
var TEXT_VARIABLES = {
version: '2.2.6',
sources: {
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
jquery: '/assets/js/jquery.min.js',
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
gitalk: {
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
},
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
},
site: {
toc: {
selectors: 'h1,h2,h3'
}
},
paths: {
search_js: '/assets/search.js'
}
};
window.TEXT_VARIABLES = TEXT_VARIABLES;
})();
</script>
</head>
<body>
<div class="root" data-is-touch="false">
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
<div class="header__title">
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
<!-- Champ de recherche -->
<div id="searchbox" class="search search--dark" style="visibility: visible">
<div class="main">
<div class="search__header"></div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<!-- <div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div> -->
</div>
</div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
json: '/search.json',
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date}&nbsp;{title}</a></li>'
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a></li>'
})
</script>
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/aide-jekyll-text-theme.html">Aide</a></li></ul>
</nav></div>
</header>
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">PhpMyAdmin (gestionnaire bases mysql/mariadb)</h1></header></div><meta itemprop="headline" content="PhpMyAdmin (gestionnaire bases mysql/mariadb)"><div class="article__info clearfix"><ul class="left-col menu"><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=debian">debian</a>
</li><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=serveur">serveur</a>
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">21&nbsp;févr.&nbsp;2020</span></li></ul></div><meta itemprop="datePublished" content="2020-02-21T00:00:00+01:00">
<meta itemprop="keywords" content="debian,serveur"><div class="js-article-content">
<div class="layout--article"><!-- start custom article top snippet -->
<style>
#myBtn {
display: none;
position: fixed;
bottom: 10px;
right: 10px;
z-index: 99;
font-size: 12px;
font-weight: bold;
border: none;
outline: none;
background-color: white;
color: black;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
#myBtn:hover {
background-color: #555;
}
</style>
<button onclick="topFunction()" id="myBtn" title="Haut de page">&#8679;</button>
<script>
//Get the button
var mybutton = document.getElementById("myBtn");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
mybutton.style.display = "block";
} else {
mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><details>
<summary><b>Afficher/cacher Sommaire</b></summary>
<!-- affichage sommaire -->
<div class="toc-aside js-toc-root"></div>
</details><h2 id="phpmyadmin">PhpMyAdmin</h2>
<ul>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-phpmyadmin-with-nginx-on-a-debian-9-server">How to Install and Secure phpMyAdmin with Nginx on a Debian 9 server</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-install-phpmyadmin-from-source-debian-10">How To Install phpMyAdmin From Source on Debian 10</a></li>
<li><a href="https://linuxize.com/post/how-to-create-mysql-user-accounts-and-grant-privileges/">How to Create MySQL Users Accounts and Grant Privileges</a></li>
</ul>
<p>introduction</p>
<p>Alors que de nombreux utilisateurs ont besoin des fonctionnalités dun système de gestion de base de données tel que MariaDB, ils peuvent ne pas se sentir à laise dinteragir avec le système uniquement à partir de linvite de MariaDB.</p>
<p>phpMyAdmin a été créé pour permettre aux utilisateurs dinteragir avec MariaDB via une interface Web. Dans ce guide, nous verrons comment installer et sécuriser phpMyAdmin afin que vous puissiez lutiliser en toute sécurité pour gérer vos bases de données sur un système Debian 10.
Conditions préalables</p>
<p>Avant de commencer avec ce guide, vous aurez besoin des éléments suivants:</p>
<ul>
<li>Accès à un serveur Debian 10. Ce serveur doit avoir un utilisateur non root avec des privilèges sudo et un pare-feu .</li>
<li>Une pile LEMP ( Linux, Nginx, MariaDB et PHP) installée sur votre serveur Debian 10.</li>
</ul>
<blockquote>
<p>Remarque: MariaDB est un fork de MySQL développé par la communauté. Bien que les deux programmes soient étroitement liés, ils ne sont pas complètement interchangeables. Bien que phpMyAdmin ait été spécialement conçu pour gérer les bases de données MySQL et fasse référence à MySQL dans diverses boîtes de dialogue, soyez assuré que votre installation de MariaDB fonctionnera correctement avec phpMyAdmin.</p>
</blockquote>
<p>Enfin, il existe des considérations de sécurité importantes lors de lutilisation de logiciels tels que phpMyAdmin, dans la mesure où:</p>
<ul>
<li>Communique directement avec votre installation MariaDB</li>
<li>Gère lauthentification à laide des informations didentification MariaDB</li>
<li>Exécute et renvoie les résultats pour des requêtes SQL arbitraires</li>
</ul>
<blockquote>
<p><em>Pour ces raisons, et parce quil sagit dune application PHP largement déployée et fréquemment attaquée, vous ne devez jamais exécuter phpMyAdmin sur des systèmes distants via une simple connexion HTTP.</em></p>
</blockquote>
<h3 id="installer-phpmyadmin-et-les-paquetages-recommandés">Installer phpMyAdmin et les paquetages recommandés</h3>
<p>Avant dinstaller et de configurer phpMyAdmin, la documentation officielle vous recommande dinstaller quelques extensions PHP sur votre serveur pour activer certaines fonctionnalités et améliorer les performances.</p>
<p>Il est recommandé dinstaller en supplément ces packages:</p>
<ul>
<li>php-mbstring : une extension PHP utilisée pour gérer des chaînes non-ASCII et convertir des chaînes en différents encodages</li>
<li>php-zip : un module PHP qui supporte le téléchargement de fichiers .zip vers phpMyAdmin</li>
<li>php-gd : un autre module PHP, celui-ci permet de supporter la bibliothèque graphique GD</li>
</ul>
<p>Mettre à jour lindex de paquet de votre serveur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo apt update
</code></pre></div></div>
<p>Ensuite, utilisez apt pour extraire les fichiers et les installer sur votre système:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo apt installer php-mbstring php-zip php-gd
</code></pre></div></div>
<p>Ensuite, nous pouvons installer phpMyAdmin. Au moment de la rédaction de ce document, phpMyAdmin nest pas disponible à partir des référentiels Debian par défaut. Vous devrez donc télécharger le code source sur votre serveur à partir du site phpMyAdmin.</p>
<p>Pour ce faire, naviguez jusquà la <a href="https://www.phpmyadmin.net/downloads/">page de téléchargements phpMyAdmin</a> , faites défiler jusquau tableau contenant les liens de téléchargement de la dernière version stable et copiez le lien de téléchargement se terminant par tar.gz Ce lien pointe vers un fichier archive connu sous le nom d archive tar qui, une fois extrait, créera un certain nombre de fichiers sur votre système. Au moment décrire ces lignes, la dernière version est la version 4.9.1.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> wget https://files.phpmyadmin.net/phpMyAdmin/4.9.1/phpMyAdmin-4.9.1-all-languages.tar.gz
</code></pre></div></div>
<p>Extrayez ensuite larchive:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> tar xvf phpMyAdmin-4.9.1-all-languages.tar.gz
</code></pre></div></div>
<p>Cela créera un certain nombre de nouveaux fichiers et répertoires sur votre serveur sous un répertoire parent nommé phpMyAdmin-4.9.1-all-languages</p>
<p>Puis exécutez la commande suivante. Cela déplacera le phpMyAdmin- 4.9.0.1 - all-languages et tous ses sous-répertoires vers le /usr/share/ , lemplacement où phpMyAdmin sattend à trouver ses fichiers de configuration par défaut. Il renommera également le répertoire en place simplement phpmyadmin :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo mv phpMyAdmin-4.9.1-all-languages /usr/share/phpmyadmin
</code></pre></div></div>
<p>Avec cela, vous avez installé phpMyAdmin, mais vous devez effectuer plusieurs changements de configuration pour pouvoir accéder à phpMyAdmin via un navigateur Web.</p>
<h3 id="configuration-manuelle-de-phpmyadmin">Configuration manuelle de phpMyAdmin</h3>
<p>Lors de linstallation de phpMyAdmin avec un gestionnaire de paquets, comme cest le cas dans un environnement Ubuntu, phpMyAdmin utilise par défaut le mode «Configuration zéro» qui effectue automatiquement plusieurs actions pour configurer le programme. Comme nous lavons installé à partir des sources dans ce guide, nous devrons effectuer ces étapes manuellement.</p>
<p>Pour commencer, créez un nouveau répertoire où phpMyAdmin stockera ses fichiers temporaires:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo mkdir -p /var/lib/phpmyadmin/tmp
</code></pre></div></div>
<p>Définissez www-data - le profil utilisateur Linux que les serveurs Web tels quApache utilisent par défaut pour les opérations normales sur les systèmes Ubuntu et Debian - en tant que propriétaire de ce répertoire:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo chown -R www-data:www-data /var/lib/phpmyadmin
</code></pre></div></div>
<p>Les fichiers que vous avez extraits précédemment incluent un exemple de fichier de configuration que vous pouvez utiliser comme fichier de configuration de base. Faites une copie de ce fichier en le conservant dans le /usr/share/phpmyadmin et renommez-le config.inc.php :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo cp /usr/share/phpmyadmin/config.sample.inc.php /usr/share/phpmyadmin/config.inc.php
</code></pre></div></div>
<p>Ouvrez ce fichier en utilisant votre éditeur de texte préféré. Ici, nous allons utiliser le nano :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo nano /usr/share/phpmyadmin/config.inc.php
</code></pre></div></div>
<p>phpMyAdmin utilise la méthode dauthentification par cookie par défaut, qui vous permet de vous connecter à phpMyAdmin comme nimporte quel utilisateur MariaDB valide à laide de cookies . Dans cette méthode, le mot de passe de lutilisateur MariaDB est stocké et crypté avec l algorithme Advanced Encryption Standard (AES) dans un cookie temporaire.</p>
<p>Historiquement, phpMyAdmin utilisait à la place le chiffre de Blowfish à cette fin, et cela est toujours reflété dans son fichier de configuration. Faites défiler jusquà la ligne commençant par $cfg[blowfish_secret] . Il ressemblera à ceci:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo nano /usr/share/phpmyadmin/config.inc.php
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> . . .
$cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
. . .
</code></pre></div></div>
<p>Entre les guillemets simples, entrez une chaîne de 32 caractères aléatoires. Ce nest pas une phrase secrète dont vous devez vous rappeler, elle sera simplement utilisée en interne par lalgorithme AES:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo nano /usr/share/phpmyadmin/config.inc.php
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> . . .
$cfg['blowfish_secret'] = ' STRINGOFTHIRTYTWORANDOMCHARACTERS '; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
. . .
</code></pre></div></div>
<p>Remarque: si la phrase secrète que vous entrez ici a moins de 32 caractères, les cookies cryptés seront moins sécurisés. Entrer une chaîne de plus de 32 caractères ne causera toutefois aucun préjudice.</p>
<p>Pour générer une chaîne de caractères vraiment aléatoire, vous pouvez installer et utiliser le programme pwgen :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo apt install pwgen
</code></pre></div></div>
<p>Par défaut, pwgen crée des pwgen faciles à prononcer, bien que moins sécurisés. Cependant, en incluant lindicateur -s , comme dans la commande suivante, vous pouvez créer un mot de passe complètement aléatoire et difficile à mémoriser. Notez les deux derniers arguments de cette commande: 32 , qui pwgen la longueur de la chaîne de mot de passe générée par pwgen ; et 1 qui indique à pwgen le nombre de chaînes quil doit générer:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> pwgen -s 32 1
</code></pre></div></div>
<p>Ensuite, faites défiler jusquau commentaire qui lit <code class="language-plaintext highlighter-rouge">/* User used to manipulate with storage */</code> Cette section inclut certaines directives qui définissent un utilisateur de la base de données MariaDB nommé pma qui effectue certaines tâches administratives dans phpMyAdmin. Selon la documentation officielle , ce compte utilisateur spécial nest pas nécessaire dans les cas où un seul utilisateur aura accès à phpMyAdmin, mais il est recommandé dans les scénarios multi-utilisateurs.</p>
<p>Supprimez les controlpass directives controluser et controlpass en supprimant les barres obliques précédentes. Puis mettez à jour la directive controlpass pour quelle pointe vers un mot de passe sécurisé de votre choix. Si vous ne le faites pas, le mot de passe par défaut restera en place et des utilisateurs inconnus pourraient facilement accéder à votre base de données via linterface phpMyAdmin.</p>
<p>Après avoir apporté ces modifications, cette section du fichier ressemblera à ceci:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>. . .
/* User used to manipulate with storage */
// $cfg['Servers'][$i]['controlhost'] = '';
// $cfg['Servers'][$i]['controlport'] = '';
$cfg['Servers'][$i]['controluser'] = 'pma';
$cfg['Servers'][$i]['controlpass'] = 'password';
. . .
</code></pre></div></div>
<p>En dessous de cette section, vous trouverez une autre section précédée dun commentaire intitulé <code class="language-plaintext highlighter-rouge">/* Storage database and tables */</code> . Cette section inclut un certain nombre de directives qui définissent le stockage de configuration de phpMyAdmin , une base de données et plusieurs tables utilisées par lutilisateur de la base de données administrative pma . Ces tables permettent dactiver un certain nombre de fonctionnalités de phpMyAdmin, notamment les signets, les commentaires, la génération de PDF, etc.</p>
<p>Supprimez la mise en commentaire de chaque ligne de cette section en supprimant les barres obliques au début de chaque ligne pour donner lapparence suivante:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>. . .
/* Storage database and tables */
$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
$cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
$cfg['Servers'][$i]['relation'] = 'pma__relation';
$cfg['Servers'][$i]['table_info'] = 'pma__table_info';
$cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
$cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
$cfg['Servers'][$i]['column_info'] = 'pma__column_info';
$cfg['Servers'][$i]['history'] = 'pma__history';
$cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
$cfg['Servers'][$i]['tracking'] = 'pma__tracking';
$cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
$cfg['Servers'][$i]['recent'] = 'pma__recent';
$cfg['Servers'][$i]['favorite'] = 'pma__favorite';
$cfg['Servers'][$i]['users'] = 'pma__users';
$cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
$cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
$cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
$cfg['Servers'][$i]['central_columns'] = 'pma__central_columns';
$cfg['Servers'][$i]['designer_settings'] = 'pma__designer_settings';
$cfg['Servers'][$i]['export_templates'] = 'pma__export_templates';
. . .
</code></pre></div></div>
<p>Ces tables nexistent pas encore, mais nous les créerons sous peu.</p>
<p>Enfin, faites défiler vers le bas du fichier et ajoutez la ligne suivante. Cela configurera phpMyAdmin pour utiliser le /var/lib/phpmyadmin/tmp vous avez créé précédemment en tant que répertoire temporaire. phpMyAdmin utilisera ce répertoire temporaire comme cache de modèles, ce qui permet un chargement plus rapide des pages:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$cfg['TempDir'] = '/var/lib/phpmyadmin/tmp';
</code></pre></div></div>
<p>Enregistrez et fermez le fichier après avoir ajouté cette ligne. Si vous avez utilisé nano , vous pouvez le faire en appuyant sur CTRL + X , Y , puis sur ENTER .</p>
<p>Ensuite, vous devrez créer la base de données de stockage phpMyAdmin et ses tables. Lorsque vous avez installé phpMyAdmin à létape précédente, il sest accompagné dun fichier nommé create_tables.sql . Ce fichier SQL contient toutes les commandes nécessaires à la création de la base de données de stockage de la configuration et des tables nécessaires au bon fonctionnement de phpMyAdmin.</p>
<p>Exécutez la commande suivante pour utiliser le fichier create_tables.sql afin de créer la base de données de stockage de configuration et les tables:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo -s
mysql -uroot -p$(cat /etc/mysql/mdp) &lt; /usr/share/phpmyadmin/sql/create_tables.sql
</code></pre></div></div>
<p>Ensuite, vous devrez créer lutilisateur administratif pma <br />
Assurez-vous de changer le password de password pour laligner sur le mot de passe que vous avez défini dans le fichier config.inc.php :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> mysql -uroot -p$(cat /etc/mysql/mdp) -e "GRANT SELECT, INSERT, UPDATE, DELETE ON phpmyadmin.* TO 'pma'@'localhost' IDENTIFIED BY 'qzbXEHio0lwq';"
</code></pre></div></div>
<p>Si vous nen avez pas déjà créé, vous devez également créer un utilisateur MariaDB habituel dans le but de gérer des bases de données via phpMyAdmin, car il est recommandé de vous connecter avec un autre compte que lutilisateur pma . <br />
Vous pouvez créer un utilisateur disposant de privilèges sur toutes les tables de la base de données, ainsi que du pouvoir dajouter, de modifier et de supprimer des privilèges dutilisateur, à laide de cette commande. Quels que soient les privilèges que vous attribuez à cet utilisateur, veillez également à lui attribuer un mot de passe fort:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> mysql -uroot -p$(cat /etc/mysql/mdp) -e "GRANT ALL PRIVILEGES ON *.* TO 'yanspm'@'localhost' IDENTIFIED BY 'DxShMzcc4v' WITH GRANT OPTION;"
</code></pre></div></div>
<h2 id="sécuriser-phpmyadmin">Sécuriser PhpMyAdmin</h2>
<h3 id="brouiller-les-pistes">Brouiller les pistes</h3>
<p>Lun des moyens les plus élémentaires de protéger votre installation de phpMyAdmin est de le rendre plus difficile à trouver. Les robots rechercheront des chemins communs, tels que /phpmyadmin , /pma , /admin , /mysql et autres. Si vous modifiez lURL de linterface de /phpmyadmin en un nom non standard, les scripts automatisés auront beaucoup plus de difficulté à trouver votre installation phpMyAdmin et à tenter des attaques en force.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ln -s /usr/share/phpmyadmin /var/www/default-www/rienavoir
</code></pre></div></div>
<h3 id="désactivation-de-la-connexion-root">Désactivation de la connexion root</h3>
<p>Sur MySQL ainsi que sur les systèmes Linux classiques, le compte root est un compte administratif spécial avec un accès illimité au système. En plus dêtre un compte privilégié, cest un nom dutilisateur connu, ce qui en fait une cible évidente pour les attaques par force brute. Pour minimiser les risques, nous allons configurer phpMyAdmin pour quil refuse toute tentative de connexion venant de la racine de lutilisateur. Ainsi, même si vous fournissez des informations didentification valides pour lutilisateur racine , vous obtiendrez toujours une erreur «accès refusé» et vous ne serez pas autorisé à vous connecter.</p>
<p>Comme nous avons choisi dutiliser dbconfig-common pour configurer et stocker les paramètres de phpMyAdmin, la configuration par défaut est actuellement stockée dans la base de données. Nous devrons créer un nouveau fichier <strong>config.inc.php</strong> pour définir nos paramètres personnalisés.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo nano /usr/share/phpmyadmin/config.inc.php
</code></pre></div></div>
<p>désactiver les connexions sans mot de passe ( AllowNoPassword défini sur false ) et la connexion racine ( AllowRoot définie sur false ):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;?php
[...]
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['AllowNoPassword'] = false;
$cfg['Servers'][$i]['AllowRoot'] = false;
</code></pre></div></div>
<p>Les modifications sappliqueront automatiquement. Si vous rechargez la page de connexion maintenant et essayez de vous connecter en tant que root, vous obtiendrez une erreur d accès refusé :</p>
<p><img src="/images/pma001.png" alt="Texte alternatif" width="300" /></p>
<p>La connexion racine est maintenant interdite sur votre installation de phpMyAdmin. Cette mesure de sécurité empêchera les scripts brute-force dessayer de deviner le mot de passe de la base de données racine sur votre serveur. De plus, il imposera lutilisation de comptes MySQL moins privilégiés pour accéder à linterface Web de phpMyAdmin, qui constitue en soi une pratique de sécurité importante.</p>
<h3 id="création-dune-passerelle-dauthentification">Création dune passerelle dauthentification</h3>
<p>Cacher votre installation de phpMyAdmin à un emplacement inhabituel peut éviter certains robots automatisés analysant le réseau, mais il est inutile contre les attaques ciblées. Pour mieux protéger une application Web à accès restreint, il est généralement plus efficace darrêter les attaquants avant quils ne puissent même accéder à lapplication. De cette manière, ils ne pourront pas utiliser les exploits génériques ni les attaques par force brute pour deviner les informations daccès.</p>
<p>Dans le cas spécifique de phpMyAdmin, il est encore plus important de garder linterface de connexion sous clé. En restant ouvert au monde, vous offrez une plate-forme de force brute permettant aux attaquants de deviner les informations didentification de votre base de données.</p>
<p>Ajouter une couche supplémentaire dauthentification à votre installation phpMyAdmin vous permet daccroître la sécurité. Les utilisateurs devront passer par une invite dauthentification HTTP avant de voir lécran de connexion phpMyAdmin. La plupart des serveurs Web, y compris Nginx, fournissent cette fonctionnalité de manière native.</p>
<p>Pour le configurer, nous devons dabord créer un fichier de mots de passe pour stocker les informations dauthentification. Nginx exige que les mots de passe soient chiffrés à laide de la fonction crypt() . La suite OpenSSL, qui devrait déjà être installée sur votre serveur, inclut cette fonctionnalité.</p>
<p>Pour créer un fichier dauthentification avec un mot de passe crypté</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo sh -c "echo -n 'yanspm:' &gt;&gt; /etc/nginx/.pma_pass"
sudo sh -c "openssl passwd -apr1 &gt;&gt; /etc/nginx/.pma_pass"
</code></pre></div></div>
<p>Vous serez invité à entrer et à confirmer le mot de passe que vous souhaitez utiliser.
Ce fichier est constitué du nom dutilisateur suivi de deux points (:), suivi de la version chiffrée du mot de passe.</p>
<p>Nous sommes maintenant prêts à modifier le fichier de configuration Nginx. Vous devez utiliser le fichier de configuration Nginx approprié pour lemplacement Web où phpMyAdmin est actuellement hébergé. Ouvrez ce fichier dans votre éditeur de texte pour commencer:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo nano /etc/nginx/conf.d//xoyize.xyz.d/phpadmin.conf
</code></pre></div></div>
<p>Localisez le bloc server et son location / section. Dans ce bloc, nous devrons définir deux directives différentes: auth_basic , qui définit le message qui sera affiché sur linvite dauthentification, et auth_basic_user_file , pointant vers le fichier que nous venons de créer. Voici à quoi devrait ressembler votre fichier de configuration lorsque vous aurez terminé:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>location /rienavoir {
auth_basic "Admin Login";
auth_basic_user_file /etc/nginx/.pma_pass;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock; # PHP7.3
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
</code></pre></div></div>
<p>Enregistrez et fermez le fichier lorsque vous avez terminé. Pour vérifier si le fichier de configuration est valide, vous pouvez exécuter:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo nginx -t
</code></pre></div></div>
<p>Pour activer le nouveau portail dauthentification, vous devez recharger le serveur Web:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo systemctl reload nginx
</code></pre></div></div>
<p>Maintenant, si vous visitez lURL phpMyAdmin dans votre navigateur Web, le nom dutilisateur et le mot de passe que vous avez ajoutés au fichier .pma_pass : https://xoyize.xyz/rienavoir</p>
<p><img src="/images/pma002.png" alt="Page d'authentification Nginx" width="300" /></p>
<p>Une fois que vous avez entré vos identifiants, vous serez redirigé vers la page de connexion standard de phpMyAdmin.</p>
<blockquote>
<p>Remarque: Si lactualisation de la page ne fonctionne pas, vous devrez peut-être effacer votre cache ou utiliser une session de navigateur différente si vous avez déjà utilisé phpMyAdmin.</p>
</blockquote>
<p>En plus de fournir une couche de sécurité supplémentaire, cette passerelle aidera à garder vos journaux MySQL à labri des tentatives dauthentification spammeuses.</p>
<h3 id="configuration-de-laccès-via-des-tunnels-cryptés-facultatif">Configuration de laccès via des tunnels cryptés (facultatif)</h3>
<p>Pour plus de sécurité, il est possible de verrouiller votre installation phpMyAdmin sur des hôtes autorisés uniquement. Vous pouvez ajouter des hôtes autorisés à la liste blanche dans votre fichier de configuration Nginx, de sorte que toute demande provenant dune adresse IP ne figurant pas sur la liste soit refusée.</p>
<p>Même si cette fonctionnalité seule peut suffire dans certains cas dutilisation, ce nest pas toujours la meilleure solution à long terme, principalement en raison du fait que la plupart des gens naccèdent pas à Internet à partir dadresses IP statiques. Dès que vous obtenez une nouvelle adresse IP auprès de votre fournisseur Internet, vous ne pourrez plus accéder à linterface phpMyAdmin tant que vous naurez pas mis à jour le fichier de configuration Nginx avec votre nouvelle adresse IP.</p>
<p>Pour une solution à long terme plus robuste, vous pouvez utiliser le contrôle daccès basé sur IP pour créer une configuration dans laquelle les utilisateurs nauront accès à votre interface phpMyAdmin que sils accèdent à partir dune adresse IP autorisée ou dun hôte local via un tunnel SSH . Nous verrons comment le configurer dans les sections ci-dessous.</p>
<p>La combinaison du contrôle daccès basé sur IP avec le tunneling SSH augmente considérablement la sécurité car elle bloque totalement les accès provenant de linternet public (à lexception des IP autorisées), en plus de fournir un canal sécurisé entre lutilisateur et le serveur via lutilisation de tunnels chiffrés.</p>
<h4 id="configuration-nginx-du-contrôle-daccès-basé-sur-ip">Configuration Nginx du contrôle daccès basé sur IP</h4>
<p>Sur Nginx, le contrôle daccès basé sur IP peut être défini dans le bloc <code class="language-plaintext highlighter-rouge">location</code> correspondant dun site donné, à laide des directives <code class="language-plaintext highlighter-rouge">allow</code> et <code class="language-plaintext highlighter-rouge">deny</code> . Par exemple, si nous voulons autoriser uniquement les demandes provenant dun hôte donné, nous devons inclure les deux lignes suivantes, dans cet ordre, à lintérieur du bloc <code class="language-plaintext highlighter-rouge">location</code> correspondant au site que nous souhaitons protéger:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>allow hostname_or_IP;
deny all;
</code></pre></div></div>
<p>Vous pouvez autoriser autant dhôtes que vous le souhaitez. Il vous suffit dinclure une ligne dautorisation (<code class="language-plaintext highlighter-rouge">allow</code>) pour chaque hôte / IP autorisé à lintérieur du bloc <code class="language-plaintext highlighter-rouge">location</code> correspondant au site que vous protégez. Les directives seront évaluées dans le même ordre où elles sont répertoriées, jusquà ce quune correspondance soit trouvée ou que la demande soit finalement refusée en raison de la directive <code class="language-plaintext highlighter-rouge">deny all</code></p>
<p>Nous allons maintenant configurer Nginx pour nautoriser que les requêtes provenant de localhost ou de votre adresse IP actuelle. Tout dabord, vous devez connaître ladresse IP publique actuelle utilisée par votre ordinateur local pour se connecter à Internet. Il y a différentes façons dobtenir cette information. pour plus de simplicité, nous allons utiliser le service fourni par ipinfo.io . Vous pouvez soit ouvrir lURL <a href="https://ipinfo.io/ip">https://ipinfo.io/ip</a> dans votre navigateur, soit exécuter la commande suivante à partir de votre ordinateur local :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl https://ipinfo.io/ip
</code></pre></div></div>
<p>Vous devriez obtenir une adresse IP simple en sortie, comme ceci:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>203.0.113.111
</code></pre></div></div>
<p>Cest votre adresse IP publique actuelle. Nous allons configurer le bloc demplacement de phpMyAdmin pour nautoriser que les requêtes provenant de cette adresse IP, en plus de localhost. Nous devrons éditer encore une fois le bloc de configuration pour phpMyAdmin dans /etc/nginx/sites-available/ example.com .</p>
<p>Ouvrez le fichier de configuration Nginx à laide de léditeur de ligne de commande de votre choix:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo nano /etc/nginx/sites-available/example.com
</code></pre></div></div>
<p>Comme nous avons déjà une règle daccès dans notre configuration actuelle, nous devons la combiner avec un contrôle daccès basé sur IP à laide de la directive satisfy all . De cette façon, nous pouvons conserver linvite dauthentification HTTP actuelle pour une sécurité accrue.</p>
<p>Voici à quoi devrait ressembler votre configuration de phpMyAdmin Nginx après lédition:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
. . .
location /nothingtosee {
satisfy all; #requires both conditions
allow 203.0.113.111; #allow your IP
allow 127.0.0.1; #allow localhost via SSH tunnels
deny all; #deny all other sources
auth_basic "Admin Login";
auth_basic_user_file /etc/nginx/pma_pass;
}
. . .
}
</code></pre></div></div>
<p>Rappelez-vous de ne rien remplacer par le chemin daccès réel où se trouve phpMyAdmin et ladresse IP en surbrillance par votre adresse IP publique actuelle(nothingtosee et 203.0.113.111).</p>
<p>Enregistrez et fermez le fichier lorsque vous avez terminé. Pour vérifier si le fichier de configuration est valide, vous pouvez exécuter:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo nginx -t
</code></pre></div></div>
<p>Rechargez maintenant le serveur Web pour que les modifications prennent effet:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> sudo systemctl reload nginx
</code></pre></div></div>
<p>Étant donné que votre adresse IP est explicitement répertoriée en tant quhôte autorisé, votre accès ne doit pas être perturbé. Toute personne essayant daccéder à votre installation phpMyAdmin recevra maintenant une erreur 403 (interdite):</p>
<p>https://server_domain_or_IP/nothingtosee</p>
<p><img src="/images/pma003.png" alt="" /></p>
<p>Dans la section suivante, nous verrons comment utiliser le tunneling SSH pour accéder au serveur Web via des requêtes locales. De cette façon, vous pourrez toujours accéder à linterface de phpMyAdmin même lorsque votre adresse IP changera.</p>
<h3 id="accéder-à-phpmyadmin-via-un-tunnel-crypté">Accéder à phpMyAdmin via un tunnel crypté</h3>
<p>Le tunneling SSH fonctionne comme un moyen de rediriger le trafic réseau via des canaux cryptés. En exécutant une commande ssh similaire à celle que vous utiliseriez pour vous connecter à un serveur, vous pouvez créer un «tunnel» sécurisé entre votre ordinateur local et ce serveur. Tout le trafic entrant sur un port local donné peut maintenant être redirigé via le tunnel crypté et utiliser le serveur distant en tant que proxy, avant de recourir à Internet. Cela ressemble à ce qui se passe lorsque vous utilisez un VPN ( réseau privé virtuel ), mais la tunnelisation SSH est beaucoup plus simple à configurer.</p>
<p>Nous utiliserons le tunneling SSH pour envoyer par proxy nos demandes au serveur Web distant exécutant phpMyAdmin. En créant un tunnel entre votre machine locale et le serveur sur lequel phpMyAdmin est installé, vous pouvez rediriger les demandes locales vers le serveur Web distant. De plus, le trafic sera crypté et les demandes atteindront Nginx comme si elles venaient de localhost . Ainsi, quelle que soit ladresse IP à laquelle vous vous connectez, vous pourrez accéder en toute sécurité à linterface de phpMyAdmin.</p>
<p>Étant donné que le trafic entre votre machine locale et le serveur Web distant sera chiffré, il sagit dune alternative sûre dans les situations où vous ne pouvez pas installer de certificat SSL / TLS sur le serveur Web exécutant phpMyAdmin.</p>
<p>Depuis votre ordinateur local , lancez cette commande chaque fois que vous avez besoin daccéder à phpMyAdmin:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ssh user@server_domain_or_IP -L 8000:localhost:80 -L 8443:localhost:443 -N
</code></pre></div></div>
<p>Examinons chaque partie de la commande:</p>
<ul>
<li><strong>user</strong> : utilisateur SSH pour se connecter au serveur sur lequel phpMyAdmin est en cours dexécution</li>
<li><strong>server_domain_or_IP</strong> : hôte SSH où phpMyAdmin est en cours dexécution</li>
<li><strong>-L 8000:localhost:80</strong> redirige le trafic HTTP sur le port 8000</li>
<li><strong>-L 8443:localhost:443</strong> redirige le trafic HTTPS sur le port 8443</li>
<li><strong>-N</strong> : nexécute pas de commandes à distance</li>
</ul>
<p>Remarque: cette commande bloquera le terminal jusquà ce quelle soit interrompue par un CTRL+C , auquel cas elle mettra fin à la connexion SSH et arrêtera la redirection de paquets. Si vous préférez exécuter cette commande en arrière-plan, vous pouvez utiliser SSH avec loption <code class="language-plaintext highlighter-rouge">-f</code></p>
<p>Maintenant, allez dans votre navigateur et remplacez <strong>server_domain_or_IP</strong> par <code class="language-plaintext highlighter-rouge">localhost:PORT</code> , où PORT correspond à 8000 pour HTTP ou 8443 à HTTPS:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://localhost:8000/nothingtosee
https://localhost:443/nothingtosee
</code></pre></div></div>
<p>Ecran de connexion phpMyAdmin</p>
<blockquote>
<p>Remarque: Si vous accédez à phpMyAdmin via https , vous pourriez recevoir un message dalerte mettant en cause la sécurité du certificat SSL. Cela se produit parce que le nom de domaine que vous utilisez (localhost) ne correspond pas à ladresse enregistrée dans le certificat (domaine dans lequel phpMyAdmin est actuellement desservi). Il est prudent de procéder.</p>
</blockquote>
<p>Toutes les demandes sur <strong>localhost:8000</strong> (HTTP) et <strong>localhost:8443</strong> (HTTPS) sont maintenant redirigées via un tunnel sécurisé vers votre application phpMyAdmin distante. Non seulement vous avez renforcé la sécurité en désactivant laccès public à votre phpMyAdmin, mais vous avez également protégé tout le trafic entre votre ordinateur local et le serveur distant en utilisant un tunnel crypté pour envoyer et recevoir des données.</p>
<p>Si vous souhaitez imposer lutilisation du tunnel SSH à toute personne souhaitant accéder à votre interface phpMyAdmin (vous inclus), vous pouvez le faire en supprimant toute autre adresse IP autorisée du fichier de configuration de Nginx, en laissant <strong>127.0.0.1</strong> comme seule autorisation autorisée. hôte pour accéder à cet emplacement. Étant donné que personne ne sera en mesure de faire des demandes directes à phpMyAdmin, il est prudent de supprimer lauthentification HTTP afin de simplifier votre configuration. Voici à quoi ressemblerait votre fichier de configuration dans un tel scénario:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/nginx/sites-available/example.com
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
. . .
location /nothingtosee {
allow 127.0.0.1; #allow localhost only
deny all; #deny all other sources
}
. . .
}
</code></pre></div></div>
<p>Une fois que vous rechargerez la configuration de Nginx avec sudo systemctl reload nginx , votre installation de phpMyAdmin sera verrouillée et les utilisateurs devront utiliser des tunnels SSH pour accéder à linterface de phpMyAdmin via des requêtes redirigées.</p>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2020-02-21T00:00:00+01:00"><!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<!--
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2020/02/20/Comment_convertir_des_packages_DEB_en_packages_Linux_Arch.html">debtap ou comment convertir des packages deb en Linux Arch</a></div><div class="next"><span>SUIVANT</span><a href="/2020/02/25/Basculer-syst%C3%A8me-boot-MBR-vers-UEFI(GPT).html">Ordinateur Bureau PC1 démarrage UEFI (GPT)</a></div></div></div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
$(function() {
var $this ,$scroll;
var $articleContent = $('.js-article-content');
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
$scroll = $(scroll);
$articleContent.find('.highlight').each(function() {
$this = $(this);
$this.attr('data-lang', $this.find('code').attr('data-lang'));
});
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
$this = $(this);
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
});
$articleContent.on('click', '.anchor', function() {
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
});
});
});
})();
</script>
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
<!-- end custom main bottom snippet -->
</div>
</div></div></div></div>
</div><script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $body = $('body'), $window = $(window);
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
var activeCount = 0;
function modal(options) {
var $root = this, visible, onChange, hideWhenWindowScroll = false;
var scrollTop;
function setOptions(options) {
var _options = options || {};
visible = _options.initialVisible === undefined ? false : show;
onChange = _options.onChange;
hideWhenWindowScroll = _options.hideWhenWindowScroll;
}
function init() {
setState(visible);
}
function setState(isShow) {
if (isShow === visible) {
return;
}
visible = isShow;
if (visible) {
activeCount++;
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
$root.addClass('modal--show');
$pageMain.scrollTop(scrollTop);
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
$window.on('keyup', handleKeyup);
} else {
activeCount > 0 && activeCount--;
$root.removeClass('modal--show');
$window.scrollTop(scrollTop);
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
$window.off('keyup', handleKeyup);
}
onChange && onChange(visible);
}
function show() {
setState(true);
}
function hide() {
setState(false);
}
function handleKeyup(e) {
// Char Code: 27 ESC
if (e.which === 27) {
hide();
}
}
setOptions(options);
init();
return {
show: show,
hide: hide,
$el: $root
};
}
$.fn.modal = modal;
});
})();
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
(function () {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
// search panel
var search = (window.search || (window.search = {}));
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
true : window.useDefaultSearchBox ;
var $searchModal = $('.js-page-search-modal');
var $searchToggle = $('.js-search-toggle');
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
var modalVisible = false;
search.searchModal = searchModal;
var $searchBox = null;
var $searchInput = null;
var $searchClear = null;
function getModalVisible() {
return modalVisible;
}
search.getModalVisible = getModalVisible;
function handleModalChange(visible) {
modalVisible = visible;
if (visible) {
search.onShow && search.onShow();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
} else {
search.onShow && search.onHide();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
setTimeout(function() {
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
search.clear && search.clear();
window.pageAsideAffix && window.pageAsideAffix.refresh();
}, 400);
}
}
$searchToggle.on('click', function() {
modalVisible ? searchModal.hide() : searchModal.show();
});
// Char Code: 83 S, 191 /
$(window).on('keyup', function(e) {
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
modalVisible || searchModal.show();
}
});
if (useDefaultSearchBox) {
$searchBox = $('.js-search-box');
$searchInput = $searchBox.children('input');
$searchClear = $searchBox.children('.js-icon-clear');
search.getSearchInput = function() {
return $searchInput.get(0);
};
search.getVal = function() {
return $searchInput.val();
};
search.setVal = function(val) {
$searchInput.val(val);
};
$searchInput.on('focus', function() {
$(this).addClass('focus');
});
$searchInput.on('blur', function() {
$(this).removeClass('focus');
});
$searchInput.on('input', window.throttle(function() {
var val = $(this).val();
if (val === '' || typeof val !== 'string') {
search.clear && search.clear();
} else {
$searchBox.addClass('not-empty');
search.onInputNotEmpty && search.onInputNotEmpty(val);
}
}, 400));
$searchClear.on('click', function() {
$searchInput.val(''); $searchBox.removeClass('not-empty');
search.clear && search.clear();
});
}
});
})();
</script><div class="search search--dark">
<div class="main">
<div class="search__header">Recherche</div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input id="search-input" type="text" />
<div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div>
</div>
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
Annuler</button>
</div>
<div id="results-container" class="search-result js-search-result"></div>
</div>
</div>
<!-- Script pointing to search-script.js -->
<script>/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
(function(){
'use strict'
var _$Templater_7 = {
compile: compile,
setOptions: setOptions
}
const options = {}
options.pattern = /\{(.*?)\}/g
options.template = ''
options.middleware = function () {}
function setOptions (_options) {
options.pattern = _options.pattern || options.pattern
options.template = _options.template || options.template
if (typeof _options.middleware === 'function') {
options.middleware = _options.middleware
}
}
function compile (data) {
return options.template.replace(options.pattern, function (match, prop) {
const value = options.middleware(prop, data[prop], options.template)
if (typeof value !== 'undefined') {
return value
}
return data[prop] || match
})
}
'use strict';
function fuzzysearch (needle, haystack) {
var tlen = haystack.length;
var qlen = needle.length;
if (qlen > tlen) {
return false;
}
if (qlen === tlen) {
return needle === haystack;
}
outer: for (var i = 0, j = 0; i < qlen; i++) {
var nch = needle.charCodeAt(i);
while (j < tlen) {
if (haystack.charCodeAt(j++) === nch) {
continue outer;
}
}
return false;
}
return true;
}
var _$fuzzysearch_1 = fuzzysearch;
'use strict'
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
function FuzzySearchStrategy () {
this.matches = function (string, crit) {
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
}
}
'use strict'
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
function LiteralSearchStrategy () {
this.matches = function (str, crit) {
if (!str) return false
str = str.trim().toLowerCase()
crit = crit.trim().toLowerCase()
return crit.split(' ').filter(function (word) {
return str.indexOf(word) >= 0
}).length === crit.split(' ').length
}
}
'use strict'
var _$Repository_4 = {
put: put,
clear: clear,
search: search,
setOptions: __setOptions_4
}
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
function NoSort () {
return 0
}
const data = []
let opt = {}
opt.fuzzy = false
opt.limit = 10
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = NoSort
opt.exclude = []
function put (data) {
if (isObject(data)) {
return addObject(data)
}
if (isArray(data)) {
return addArray(data)
}
return undefined
}
function clear () {
data.length = 0
return data
}
function isObject (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray (obj) {
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
}
function addObject (_data) {
data.push(_data)
return data
}
function addArray (_data) {
const added = []
clear()
for (let i = 0, len = _data.length; i < len; i++) {
if (isObject(_data[i])) {
added.push(addObject(_data[i]))
}
}
return added
}
function search (crit) {
if (!crit) {
return []
}
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
}
function __setOptions_4 (_opt) {
opt = _opt || {}
opt.fuzzy = _opt.fuzzy || false
opt.limit = _opt.limit || 10
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
opt.sort = _opt.sort || NoSort
opt.exclude = _opt.exclude || []
}
function findMatches (data, crit, strategy, opt) {
const matches = []
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
const match = findMatchesInObject(data[i], crit, strategy, opt)
if (match) {
matches.push(match)
}
}
return matches
}
function findMatchesInObject (obj, crit, strategy, opt) {
for (const key in obj) {
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
return obj
}
}
}
function isExcluded (term, excludedTerms) {
for (let i = 0, len = excludedTerms.length; i < len; i++) {
const excludedTerm = excludedTerms[i]
if (new RegExp(excludedTerm).test(term)) {
return true
}
}
return false
}
/* globals ActiveXObject:false */
'use strict'
var _$JSONLoader_2 = {
load: load
}
function load (location, callback) {
const xhr = getXHR()
xhr.open('GET', location, true)
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
xhr.send()
}
function createStateChangeListener (xhr, callback) {
return function () {
if (xhr.readyState === 4 && xhr.status === 200) {
try {
callback(null, JSON.parse(xhr.responseText))
} catch (err) {
callback(err, null)
}
}
}
}
function getXHR () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
}
'use strict'
var _$OptionsValidator_3 = function OptionsValidator (params) {
if (!validateParams(params)) {
throw new Error('-- OptionsValidator: required options missing')
}
if (!(this instanceof OptionsValidator)) {
return new OptionsValidator(params)
}
const requiredOptions = params.required
this.getRequiredOptions = function () {
return requiredOptions
}
this.validate = function (parameters) {
const errors = []
requiredOptions.forEach(function (requiredOptionName) {
if (typeof parameters[requiredOptionName] === 'undefined') {
errors.push(requiredOptionName)
}
})
return errors
}
function validateParams (params) {
if (!params) {
return false
}
return typeof params.required !== 'undefined' && params.required instanceof Array
}
}
'use strict'
var _$utils_9 = {
merge: merge,
isJSON: isJSON
}
function merge (defaultParams, mergeParams) {
const mergedOptions = {}
for (const option in defaultParams) {
mergedOptions[option] = defaultParams[option]
if (typeof mergeParams[option] !== 'undefined') {
mergedOptions[option] = mergeParams[option]
}
}
return mergedOptions
}
function isJSON (json) {
try {
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
return true
}
return false
} catch (err) {
return false
}
}
var _$src_8 = {};
(function (window) {
'use strict'
let options = {
searchInput: null,
resultsContainer: null,
json: [],
success: Function.prototype,
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
templateMiddleware: Function.prototype,
sortMiddleware: function () {
return 0
},
noResultsText: 'No results found',
limit: 10,
fuzzy: false,
debounceTime: null,
exclude: []
}
let debounceTimerHandle
const debounce = function (func, delayMillis) {
if (delayMillis) {
clearTimeout(debounceTimerHandle)
debounceTimerHandle = setTimeout(func, delayMillis)
} else {
func.call()
}
}
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
/* removed: const _$Templater_7 = require('./Templater') */;
/* removed: const _$Repository_4 = require('./Repository') */;
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
const optionsValidator = _$OptionsValidator_3({
required: requiredOptions
})
/* removed: const _$utils_9 = require('./utils') */;
window.SimpleJekyllSearch = function (_options) {
const errors = optionsValidator.validate(_options)
if (errors.length > 0) {
throwError('You must specify the following required options: ' + requiredOptions)
}
options = _$utils_9.merge(options, _options)
_$Templater_7.setOptions({
template: options.searchResultTemplate,
middleware: options.templateMiddleware
})
_$Repository_4.setOptions({
fuzzy: options.fuzzy,
limit: options.limit,
sort: options.sortMiddleware,
exclude: options.exclude
})
if (_$utils_9.isJSON(options.json)) {
initWithJSON(options.json)
} else {
initWithURL(options.json)
}
const rv = {
search: search
}
typeof options.success === 'function' && options.success.call(rv)
return rv
}
function initWithJSON (json) {
_$Repository_4.put(json)
registerInput()
}
function initWithURL (url) {
_$JSONLoader_2.load(url, function (err, json) {
if (err) {
throwError('failed to get JSON (' + url + ')')
}
initWithJSON(json)
})
}
function emptyResultsContainer () {
options.resultsContainer.innerHTML = ''
}
function appendToResultsContainer (text) {
options.resultsContainer.innerHTML += text
}
function registerInput () {
options.searchInput.addEventListener('input', function (e) {
if (isWhitelistedKey(e.which)) {
emptyResultsContainer()
debounce(function () { search(e.target.value) }, options.debounceTime)
}
})
}
function search (query) {
if (isValidQuery(query)) {
emptyResultsContainer()
render(_$Repository_4.search(query), query)
}
}
function render (results, query) {
const len = results.length
if (len === 0) {
return appendToResultsContainer(options.noResultsText)
}
for (let i = 0; i < len; i++) {
results[i].query = query
appendToResultsContainer(_$Templater_7.compile(results[i]))
}
}
function isValidQuery (query) {
return query && query.length > 0
}
function isWhitelistedKey (key) {
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
}
function throwError (message) {
throw new Error('SimpleJekyllSearch --- ' + message)
}
})(window)
}());
</script>
<!-- Configuration -->
<script>
SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
noResultsText: '<p>Aucun résultat!</p>',
json: '/search.json',
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{title}</a>&nbsp;(Création {create})</li>'
})
</script>
</div></div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function scrollToAnchor(anchor, duration, callback) {
var $root = this;
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
callback && callback();
});
}
$.fn.scrollToAnchor = scrollToAnchor;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function affix(options) {
var $root = this, $window = $(window), $scrollTarget, $scroll,
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
hasInit = false, curState;
function setOptions(options) {
var _options = options || {};
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroll && (scroll = _options.scroll);
_options.disabled !== undefined && (disabled = _options.disabled);
$scrollTarget = $(scrollTarget);
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
$scroll = $(scroll);
}
function preCalc() {
top();
rootHeight = $root.outerHeight();
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
rootLeft = $root.offset().left;
}
function calc(needPreCalc) {
needPreCalc && preCalc();
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
rootBottomTop = scrollBottom - rootTop;
}
function top() {
if (curState !== 'top') {
$root.removeClass('fixed').css({
left: 0,
top: 0
});
curState = 'top';
}
}
function fixed() {
if (curState !== 'fixed') {
$root.addClass('fixed').css({
left: rootLeft + 'px',
top: 0
});
curState = 'fixed';
}
}
function bottom() {
if (curState !== 'bottom') {
$root.removeClass('fixed').css({
left: 0,
top: rootBottomTop + 'px'
});
curState = 'bottom';
}
}
function setState() {
var scrollTop = $scrollTarget.scrollTop();
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
fixed();
} else if (scrollTop < rootTop) {
top();
} else {
bottom();
}
}
function init() {
if(!hasInit) {
var interval, timeout;
calc(true); setState();
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState();
});
$window.on('resize', function() {
disabled || (calc(true), setState());
});
hasInit = true;
}
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions,
refresh: function() {
calc(true, { animation: false }); setState();
}
};
}
$.fn.affix = affix;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function toc(options) {
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
function setOptions(options) {
var _options = options || {};
_options.selectors && (selectors = _options.selectors);
_options.container && (container = _options.container);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroller && (scroller = _options.scroller);
_options.disabled !== undefined && (disabled = _options.disabled);
$headings = $(container).find(selectors).filter('[id]');
$scrollTarget = $(scrollTarget);
$scroller = $(scroller);
}
function calc() {
headingsPos = [];
$headings.each(function() {
headingsPos.push(Math.floor($(this).position().top));
});
}
function setState(element, disabled) {
var scrollTop = $scrollTarget.scrollTop(), i;
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
if (element) {
$activeCur = element;
} else {
for (i = 0; i < headingsPos.length; i++) {
if (scrollTop >= headingsPos[i]) {
$activeCur = $tocLi.eq(i);
} else {
$activeCur || ($activeCur = $tocLi.eq(i));
break;
}
}
}
$activeLast && $activeLast.removeClass('active');
($activeLast = $activeCur).addClass('active');
}
function render() {
if(!hasRendered) {
$root.append($tocUl);
$headings.each(function() {
var $this = $(this);
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
});
$tocLi = $tocUl.children('li');
$tocUl.on('click', 'a', function(e) {
e.preventDefault();
var $this = $(this);
scrolling = true;
setState($this.parent());
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
scrolling = false;
});
});
}
hasRendered = true;
}
function init() {
var interval, timeout;
if(!hasInit) {
render(); calc(); setState(null, scrolling);
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState(null, scrolling);
});
$window.on('resize', window.throttle(function() {
if (!disabled) {
render(); calc(); setState(null, scrolling);
}
}, 100));
}
hasInit = true;
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions
};
}
$.fn.toc = toc;
});
})();
/*(function () {
})();*/
</script><script>
/* toc must before affix, since affix need to konw toc' height. */(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window);
var $articleContent = $('.js-article-content');
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
var toc;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
function disabled() {
return $col2.css('display') === 'none' || !hasToc;
}
tocDisabled = disabled();
toc = $tocRoot.toc({
selectors: TOC_SELECTOR,
container: $articleContent,
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
tocDisabled = disabled();
toc && toc.setOptions({
disabled: tocDisabled
});
}, 100));
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window), $pageFooter = $('.js-page-footer');
var $pageAside = $('.js-page-aside');
var affix;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
affix = $pageAside.affix({
offsetBottom: $pageFooter.outerHeight(),
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
scroll: hasSidebar ? $('.js-page-main').children() : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
affix && affix.setOptions({
disabled: tocDisabled
});
}, 100));
window.pageAsideAffix = affix;
});
})();
</script><!---->
</div>
<script>(function () {
var $root = document.getElementsByClassName('root')[0];
if (window.hasEvent('touchstart')) {
$root.dataset.isTouch = true;
document.addEventListener('touchstart', function(){}, false);
}
})();
</script>
</body>
</html>