mirror of
https://github.com/typecho/typecho.git
synced 2025-01-16 20:18:19 +01:00
fix install
This commit is contained in:
parent
0d4299d99e
commit
2731e34db0
18
admin/css/install.css
Normal file
18
admin/css/install.css
Normal file
@ -0,0 +1,18 @@
|
||||
h1 { text-align: center; }
|
||||
|
||||
details summary { cursor: pointer; }
|
||||
|
||||
@keyframes fadein { from { opacity: 0; }
|
||||
to { opacity: 1; } }
|
||||
|
||||
form > .message { display: none; }
|
||||
|
||||
.message.fade { display: block; animation: fadein .5s linear; }
|
||||
|
||||
.message *:last-child { margin-bottom: 0; }
|
||||
|
||||
.message p { margin-top: 8px; }
|
||||
|
||||
.message p button { margin-left: 5px; }
|
||||
|
||||
.message p button:first-child { margin-left: 0; }
|
@ -237,27 +237,6 @@ select { border: 1px solid #CCC; height: 28px; }
|
||||
.profile-avatar { width: 220px; height: 220px; border-radius: 10px; }
|
||||
|
||||
/** 增加配置面板内部的错误样式 by 70 */
|
||||
/** 安装样式 @author mingcheng @date 2008-09-06 */
|
||||
/** 安装向导 */
|
||||
.typecho-install { padding-bottom: 2em; }
|
||||
|
||||
.typecho-install-patch { margin-bottom: 2em; padding: 2em 0; background-color: #292D33; color: #FFF; text-align: center; }
|
||||
|
||||
.typecho-install-patch ol { list-style: none; margin: 3em 0 1em; padding: 0; color: #999; }
|
||||
|
||||
.typecho-install-patch li { display: inline-block; margin: 0 .8em; }
|
||||
|
||||
.typecho-install-patch span { display: inline-block; margin-right: 5px; width: 20px; height: 20px; line-height: 20px; border: 2px solid #999; text-align: center; border-radius: 2em; }
|
||||
|
||||
.typecho-install-patch li.current { color: #FFF; font-weight: bold; }
|
||||
|
||||
.typecho-install-patch li.current span { border-color: #FFF; }
|
||||
|
||||
/** 安装主体内容 */
|
||||
.typecho-install .typecho-install-body input { width: 100%; }
|
||||
|
||||
.typecho-install-body .typecho-option li { margin: 1em 0; }
|
||||
|
||||
/** 欢迎界面 */
|
||||
#typecho-welcome { margin: 1em 0; padding: 1em 2em; background-color: #E9E9E6; }
|
||||
|
||||
|
@ -5,17 +5,13 @@ if (!defined('__TYPECHO_ADMIN__')) {
|
||||
|
||||
$header = '<link rel="stylesheet" href="' . Typecho_Common::url('normalize.css?v=' . $suffixVersion, $options->adminStaticUrl('css')) . '">
|
||||
<link rel="stylesheet" href="' . Typecho_Common::url('grid.css?v=' . $suffixVersion, $options->adminStaticUrl('css')) . '">
|
||||
<link rel="stylesheet" href="' . Typecho_Common::url('style.css?v=' . $suffixVersion, $options->adminStaticUrl('css')) . '">
|
||||
<!--[if lt IE 9]>
|
||||
<script src="' . Typecho_Common::url('html5shiv.js?v=' . $suffixVersion, $options->adminStaticUrl('js')) . '"></script>
|
||||
<script src="' . Typecho_Common::url('respond.js?v=' . $suffixVersion, $options->adminStaticUrl('js')) . '"></script>
|
||||
<![endif]-->';
|
||||
<link rel="stylesheet" href="' . Typecho_Common::url('style.css?v=' . $suffixVersion, $options->adminStaticUrl('css')) . '">';
|
||||
|
||||
/** 注册一个初始化插件 */
|
||||
$header = Typecho_Plugin::factory('admin/header.php')->header($header);
|
||||
|
||||
?><!DOCTYPE HTML>
|
||||
<html class="no-js">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="<?php $options->charset(); ?>">
|
||||
<meta name="renderer" content="webkit">
|
||||
|
1
admin/js/html5shiv.js
vendored
1
admin/js/html5shiv.js
vendored
@ -1 +0,0 @@
|
||||
!function(e,i){var l,m,t=e.html5||{},a=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,n="_html5shiv",c=0,o={};function s(){var e=f.elements;return"string"==typeof e?e.split(" "):e}function h(e){var t=o[e[n]];return t||(t={},c++,e[n]=c,o[c]=t),t}function u(e,t,n){return t=t||i,m?t.createElement(e):(t=(n=n||h(t)).cache[e]?n.cache[e].cloneNode():r.test(e)?(n.cache[e]=n.createElem(e)).cloneNode():n.createElem(e)).canHaveChildren&&!a.test(e)?n.frag.appendChild(t):t}function d(e){var t,n,a,r,c,o=h(e=e||i);return!f.shivCSS||l||o.hasCSS||(o.hasCSS=(n="article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}",a=(t=e).createElement("p"),t=t.getElementsByTagName("head")[0]||t.documentElement,a.innerHTML="x<style>"+n+"</style>",!!t.insertBefore(a.lastChild,t.firstChild))),m||(r=e,(c=o).cache||(c.cache={},c.createElem=r.createElement,c.createFrag=r.createDocumentFragment,c.frag=c.createFrag()),r.createElement=function(e){return f.shivMethods?u(e,r,c):c.createElem(e)},r.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+s().join().replace(/[\w\-]+/g,function(e){return c.createElem(e),c.frag.createElement(e),'c("'+e+'")'})+");return n}")(f,c.frag)),e}!function(){try{var e=i.createElement("a");e.innerHTML="<xyz></xyz>",l="hidden"in e,m=1==e.childNodes.length||function(){i.createElement("a");var e=i.createDocumentFragment();return void 0===e.cloneNode||void 0===e.createDocumentFragment||void 0===e.createElement}()}catch(e){m=l=!0}}();var f={elements:t.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:"3.7.0",shivCSS:!1!==t.shivCSS,supportsUnknownElements:m,shivMethods:!1!==t.shivMethods,type:"default",shivDocument:d,createElement:u,createDocumentFragment:function(e,t){if(e=e||i,m)return e.createDocumentFragment();for(var n=(t=t||h(e)).frag.cloneNode(),a=0,r=s(),c=r.length;a<c;a++)n.createElement(r[a]);return n}};e.html5=f,d(i)}(this,document);
|
@ -1 +0,0 @@
|
||||
!function(e){"use strict";var t,n,s,a,i;e.matchMedia=e.matchMedia||(e=e.document,n=e.documentElement,s=n.firstElementChild||n.firstChild,a=e.createElement("body"),(i=e.createElement("div")).id="mq-test-1",i.style.cssText="position:absolute;top:-100em",a.style.background="none",a.appendChild(i),function(e){return i.innerHTML='­<style media="'+e+'"> #mq-test-1 { width: 42px; }</style>',n.insertBefore(a,s),t=42===i.offsetWidth,n.removeChild(a),{matches:t,media:e}})}(this),function(g){"use strict";var c={};(g.respond=c).update=function(){};var y,x,E,v,w,i,S,T,r,C,b,$,z,M,R,o,l,e,m=[],s=function(){var t=!1;try{t=new g.XMLHttpRequest}catch(e){t=new g.ActiveXObject("Microsoft.XMLHTTP")}return function(){return t}}(),n=function(e,t){var n=s();n&&(n.open("GET",e,!0),n.onreadystatechange=function(){4!==n.readyState||200!==n.status&&304!==n.status||t(n.responseText)},4!==n.readyState&&n.send(null))},p=function(e){return e.replace(c.regex.minmaxwh,"").match(c.regex.other)};function t(){R(!0)}c.ajax=n,c.queue=m,c.unsupportedmq=p,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=g.matchMedia&&null!==g.matchMedia("only all")&&g.matchMedia("only all").matches,c.mediaQueriesSupported||(y=g.document,x=y.documentElement,E=[],v=[],w=[],i={},S=30,T=y.getElementsByTagName("head")[0]||x,r=y.getElementsByTagName("base")[0],C=T.getElementsByTagName("link"),M=function(){var e,t=y.createElement("div"),n=y.body,s=x.style.fontSize,a=n&&n.style.fontSize,i=!1;return t.style.cssText="position:absolute;font-size:1em;width:1em",n||((n=i=y.createElement("body")).style.background="none"),x.style.fontSize="100%",n.style.fontSize="100%",n.appendChild(t),i&&x.insertBefore(n,x.firstChild),e=t.offsetWidth,i?x.removeChild(n):n.removeChild(t),x.style.fontSize=s,a&&(n.style.fontSize=a),z=parseFloat(e),z},R=function(e){var t,n,s,a,i,r,o,l,m,d,h="clientWidth",u=x[h],c="CSS1Compat"===y.compatMode&&u||y.body[h]||u,p={},f=C[C.length-1],u=(new Date).getTime();if(e&&b&&u-b<S)return g.clearTimeout($),void($=g.setTimeout(R,S));for(t in b=u,E)E.hasOwnProperty(t)&&(s=null===(i=(n=E[t]).minw),a=null===(r=n.maxw),i=i&&parseFloat(i)*(-1<i.indexOf("em")?z||M():1),r=r&&parseFloat(r)*(-1<r.indexOf("em")?z||M():1),n.hasquery&&(s&&a||!(s||i<=c)||!(a||c<=r))||(p[n.media]||(p[n.media]=[]),p[n.media].push(v[n.rules])));for(o in w)w.hasOwnProperty(o)&&w[o]&&w[o].parentNode===T&&T.removeChild(w[o]);for(l in w.length=0,p)p.hasOwnProperty(l)&&(m=y.createElement("style"),d=p[l].join("\n"),m.type="text/css",m.media=l,T.insertBefore(m,f.nextSibling),m.styleSheet?m.styleSheet.cssText=d:m.appendChild(y.createTextNode(d)),w.push(m))},o=function(e,t,n){function s(e){return e.replace(c.regex.urls,"$1"+t+"$2$3")}var a=e.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),i=a&&a.length||0,r=!i&&n;(t=t.substring(0,t.lastIndexOf("/"))).length&&(t+="/"),r&&(i=1);for(var o,l,m=0;m<i;m++){r?(o=n,v.push(s(e))):(o=a[m].match(c.regex.findStyles)&&RegExp.$1,v.push(RegExp.$2&&s(RegExp.$2)));for(var d,h=(d=o.split(",")).length,u=0;u<h;u++)l=d[u],p(l)||E.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:v.length-1,hasquery:-1<l.indexOf("("),minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}R()},l=function(){var t;m.length&&(t=m.shift(),n(t.href,function(e){o(e,t.href,t.media),i[t.href]=!0,g.setTimeout(function(){l()},0)}))},(e=function(){for(var e=0;e<C.length;e++){var t=C[e],n=t.href,s=t.media,a=t.rel&&"stylesheet"===t.rel.toLowerCase();n&&a&&!i[n]&&(t.styleSheet&&t.styleSheet.rawCssText?(o(t.styleSheet.rawCssText,n,s),i[n]=!0):(/^([a-zA-Z:]*\/\/)/.test(n)||r)&&n.replace(RegExp.$1,"").split("/")[0]!==g.location.host||("//"===n.substring(0,2)&&(n=g.location.protocol+n),m.push({href:n,media:s})))}l()})(),c.update=e,c.getEmValue=M,g.addEventListener?g.addEventListener("resize",t,!1):g.attachEvent&&g.attachEvent("onresize",t))}(this);
|
301
admin/src/js/html5shiv.js
vendored
301
admin/src/js/html5shiv.js
vendored
@ -1,301 +0,0 @@
|
||||
/**
|
||||
* @preserve HTML5 Shiv v3.7.0 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
||||
*/
|
||||
;(function(window, document) {
|
||||
/*jshint evil:true */
|
||||
/** version */
|
||||
var version = '3.7.0';
|
||||
|
||||
/** Preset options */
|
||||
var options = window.html5 || {};
|
||||
|
||||
/** Used to skip problem elements */
|
||||
var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
|
||||
|
||||
/** Not all elements can be cloned in IE **/
|
||||
var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
|
||||
|
||||
/** Detect whether the browser supports default html5 styles */
|
||||
var supportsHtml5Styles;
|
||||
|
||||
/** Name of the expando, to work with multiple documents or to re-shiv one document */
|
||||
var expando = '_html5shiv';
|
||||
|
||||
/** The id for the the documents expando */
|
||||
var expanID = 0;
|
||||
|
||||
/** Cached data for each document */
|
||||
var expandoData = {};
|
||||
|
||||
/** Detect whether the browser supports unknown elements */
|
||||
var supportsUnknownElements;
|
||||
|
||||
(function() {
|
||||
try {
|
||||
var a = document.createElement('a');
|
||||
a.innerHTML = '<xyz></xyz>';
|
||||
//if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
|
||||
supportsHtml5Styles = ('hidden' in a);
|
||||
|
||||
supportsUnknownElements = a.childNodes.length == 1 || (function() {
|
||||
// assign a false positive if unable to shiv
|
||||
(document.createElement)('a');
|
||||
var frag = document.createDocumentFragment();
|
||||
return (
|
||||
typeof frag.cloneNode == 'undefined' ||
|
||||
typeof frag.createDocumentFragment == 'undefined' ||
|
||||
typeof frag.createElement == 'undefined'
|
||||
);
|
||||
}());
|
||||
} catch(e) {
|
||||
// assign a false positive if detection fails => unable to shiv
|
||||
supportsHtml5Styles = true;
|
||||
supportsUnknownElements = true;
|
||||
}
|
||||
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Creates a style sheet with the given CSS text and adds it to the document.
|
||||
* @private
|
||||
* @param {Document} ownerDocument The document.
|
||||
* @param {String} cssText The CSS text.
|
||||
* @returns {StyleSheet} The style element.
|
||||
*/
|
||||
function addStyleSheet(ownerDocument, cssText) {
|
||||
var p = ownerDocument.createElement('p'),
|
||||
parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
|
||||
|
||||
p.innerHTML = 'x<style>' + cssText + '</style>';
|
||||
return parent.insertBefore(p.lastChild, parent.firstChild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of `html5.elements` as an array.
|
||||
* @private
|
||||
* @returns {Array} An array of shived element node names.
|
||||
*/
|
||||
function getElements() {
|
||||
var elements = html5.elements;
|
||||
return typeof elements == 'string' ? elements.split(' ') : elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data associated to the given document
|
||||
* @private
|
||||
* @param {Document} ownerDocument The document.
|
||||
* @returns {Object} An object of data.
|
||||
*/
|
||||
function getExpandoData(ownerDocument) {
|
||||
var data = expandoData[ownerDocument[expando]];
|
||||
if (!data) {
|
||||
data = {};
|
||||
expanID++;
|
||||
ownerDocument[expando] = expanID;
|
||||
expandoData[expanID] = data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a shived element for the given nodeName and document
|
||||
* @memberOf html5
|
||||
* @param {String} nodeName name of the element
|
||||
* @param {Document} ownerDocument The context document.
|
||||
* @returns {Object} The shived element.
|
||||
*/
|
||||
function createElement(nodeName, ownerDocument, data){
|
||||
if (!ownerDocument) {
|
||||
ownerDocument = document;
|
||||
}
|
||||
if(supportsUnknownElements){
|
||||
return ownerDocument.createElement(nodeName);
|
||||
}
|
||||
if (!data) {
|
||||
data = getExpandoData(ownerDocument);
|
||||
}
|
||||
var node;
|
||||
|
||||
if (data.cache[nodeName]) {
|
||||
node = data.cache[nodeName].cloneNode();
|
||||
} else if (saveClones.test(nodeName)) {
|
||||
node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
|
||||
} else {
|
||||
node = data.createElem(nodeName);
|
||||
}
|
||||
|
||||
// Avoid adding some elements to fragments in IE < 9 because
|
||||
// * Attributes like `name` or `type` cannot be set/changed once an element
|
||||
// is inserted into a document/fragment
|
||||
// * Link elements with `src` attributes that are inaccessible, as with
|
||||
// a 403 response, will cause the tab/window to crash
|
||||
// * Script elements appended to fragments will execute when their `src`
|
||||
// or `text` property is set
|
||||
return node.canHaveChildren && !reSkip.test(nodeName) ? data.frag.appendChild(node) : node;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a shived DocumentFragment for the given document
|
||||
* @memberOf html5
|
||||
* @param {Document} ownerDocument The context document.
|
||||
* @returns {Object} The shived DocumentFragment.
|
||||
*/
|
||||
function createDocumentFragment(ownerDocument, data){
|
||||
if (!ownerDocument) {
|
||||
ownerDocument = document;
|
||||
}
|
||||
if(supportsUnknownElements){
|
||||
return ownerDocument.createDocumentFragment();
|
||||
}
|
||||
data = data || getExpandoData(ownerDocument);
|
||||
var clone = data.frag.cloneNode(),
|
||||
i = 0,
|
||||
elems = getElements(),
|
||||
l = elems.length;
|
||||
for(;i<l;i++){
|
||||
clone.createElement(elems[i]);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shivs the `createElement` and `createDocumentFragment` methods of the document.
|
||||
* @private
|
||||
* @param {Document|DocumentFragment} ownerDocument The document.
|
||||
* @param {Object} data of the document.
|
||||
*/
|
||||
function shivMethods(ownerDocument, data) {
|
||||
if (!data.cache) {
|
||||
data.cache = {};
|
||||
data.createElem = ownerDocument.createElement;
|
||||
data.createFrag = ownerDocument.createDocumentFragment;
|
||||
data.frag = data.createFrag();
|
||||
}
|
||||
|
||||
|
||||
ownerDocument.createElement = function(nodeName) {
|
||||
//abort shiv
|
||||
if (!html5.shivMethods) {
|
||||
return data.createElem(nodeName);
|
||||
}
|
||||
return createElement(nodeName, ownerDocument, data);
|
||||
};
|
||||
|
||||
ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
|
||||
'var n=f.cloneNode(),c=n.createElement;' +
|
||||
'h.shivMethods&&(' +
|
||||
// unroll the `createElement` calls
|
||||
getElements().join().replace(/[\w\-]+/g, function(nodeName) {
|
||||
data.createElem(nodeName);
|
||||
data.frag.createElement(nodeName);
|
||||
return 'c("' + nodeName + '")';
|
||||
}) +
|
||||
');return n}'
|
||||
)(html5, data.frag);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Shivs the given document.
|
||||
* @memberOf html5
|
||||
* @param {Document} ownerDocument The document to shiv.
|
||||
* @returns {Document} The shived document.
|
||||
*/
|
||||
function shivDocument(ownerDocument) {
|
||||
if (!ownerDocument) {
|
||||
ownerDocument = document;
|
||||
}
|
||||
var data = getExpandoData(ownerDocument);
|
||||
|
||||
if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
|
||||
data.hasCSS = !!addStyleSheet(ownerDocument,
|
||||
// corrects block display not defined in IE6/7/8/9
|
||||
'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
|
||||
// adds styling not present in IE6/7/8/9
|
||||
'mark{background:#FF0;color:#000}' +
|
||||
// hides non-rendered elements
|
||||
'template{display:none}'
|
||||
);
|
||||
}
|
||||
if (!supportsUnknownElements) {
|
||||
shivMethods(ownerDocument, data);
|
||||
}
|
||||
return ownerDocument;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The `html5` object is exposed so that more elements can be shived and
|
||||
* existing shiving can be detected on iframes.
|
||||
* @type Object
|
||||
* @example
|
||||
*
|
||||
* // options can be changed before the script is included
|
||||
* html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
|
||||
*/
|
||||
var html5 = {
|
||||
|
||||
/**
|
||||
* An array or space separated string of node names of the elements to shiv.
|
||||
* @memberOf html5
|
||||
* @type Array|String
|
||||
*/
|
||||
'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video',
|
||||
|
||||
/**
|
||||
* current version of html5shiv
|
||||
*/
|
||||
'version': version,
|
||||
|
||||
/**
|
||||
* A flag to indicate that the HTML5 style sheet should be inserted.
|
||||
* @memberOf html5
|
||||
* @type Boolean
|
||||
*/
|
||||
'shivCSS': (options.shivCSS !== false),
|
||||
|
||||
/**
|
||||
* Is equal to true if a browser supports creating unknown/HTML5 elements
|
||||
* @memberOf html5
|
||||
* @type boolean
|
||||
*/
|
||||
'supportsUnknownElements': supportsUnknownElements,
|
||||
|
||||
/**
|
||||
* A flag to indicate that the document's `createElement` and `createDocumentFragment`
|
||||
* methods should be overwritten.
|
||||
* @memberOf html5
|
||||
* @type Boolean
|
||||
*/
|
||||
'shivMethods': (options.shivMethods !== false),
|
||||
|
||||
/**
|
||||
* A string to describe the type of `html5` object ("default" or "default print").
|
||||
* @memberOf html5
|
||||
* @type String
|
||||
*/
|
||||
'type': 'default',
|
||||
|
||||
// shivs the document according to the specified `html5` object options
|
||||
'shivDocument': shivDocument,
|
||||
|
||||
//creates a shived element
|
||||
createElement: createElement,
|
||||
|
||||
//creates a shived documentFragment
|
||||
createDocumentFragment: createDocumentFragment
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// expose html5
|
||||
window.html5 = html5;
|
||||
|
||||
// shiv the document
|
||||
shivDocument(document);
|
||||
|
||||
}(this, document));
|
@ -1,237 +0,0 @@
|
||||
/*! Respond.js v1.4.2: min/max-width media query polyfill
|
||||
* Copyright 2013 Scott Jehl
|
||||
* Licensed under MIT
|
||||
* http://j.mp/respondjs */
|
||||
|
||||
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
|
||||
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
|
||||
(function(w) {
|
||||
"use strict";
|
||||
w.matchMedia = w.matchMedia || function(doc, undefined) {
|
||||
var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div");
|
||||
div.id = "mq-test-1";
|
||||
div.style.cssText = "position:absolute;top:-100em";
|
||||
fakeBody.style.background = "none";
|
||||
fakeBody.appendChild(div);
|
||||
return function(q) {
|
||||
div.innerHTML = '­<style media="' + q + '"> #mq-test-1 { width: 42px; }</style>';
|
||||
docElem.insertBefore(fakeBody, refNode);
|
||||
bool = div.offsetWidth === 42;
|
||||
docElem.removeChild(fakeBody);
|
||||
return {
|
||||
matches: bool,
|
||||
media: q
|
||||
};
|
||||
};
|
||||
}(w.document);
|
||||
})(this);
|
||||
|
||||
(function(w) {
|
||||
"use strict";
|
||||
var respond = {};
|
||||
w.respond = respond;
|
||||
respond.update = function() {};
|
||||
var requestQueue = [], xmlHttp = function() {
|
||||
var xmlhttpmethod = false;
|
||||
try {
|
||||
xmlhttpmethod = new w.XMLHttpRequest();
|
||||
} catch (e) {
|
||||
xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
return function() {
|
||||
return xmlhttpmethod;
|
||||
};
|
||||
}(), ajax = function(url, callback) {
|
||||
var req = xmlHttp();
|
||||
if (!req) {
|
||||
return;
|
||||
}
|
||||
req.open("GET", url, true);
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) {
|
||||
return;
|
||||
}
|
||||
callback(req.responseText);
|
||||
};
|
||||
if (req.readyState === 4) {
|
||||
return;
|
||||
}
|
||||
req.send(null);
|
||||
}, isUnsupportedMediaQuery = function(query) {
|
||||
return query.replace(respond.regex.minmaxwh, "").match(respond.regex.other);
|
||||
};
|
||||
respond.ajax = ajax;
|
||||
respond.queue = requestQueue;
|
||||
respond.unsupportedmq = isUnsupportedMediaQuery;
|
||||
respond.regex = {
|
||||
media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,
|
||||
keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,
|
||||
comments: /\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,
|
||||
urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,
|
||||
findStyles: /@media *([^\{]+)\{([\S\s]+?)$/,
|
||||
only: /(only\s+)?([a-zA-Z]+)\s?/,
|
||||
minw: /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,
|
||||
maxw: /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,
|
||||
minmaxwh: /\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,
|
||||
other: /\([^\)]*\)/g
|
||||
};
|
||||
respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches;
|
||||
if (respond.mediaQueriesSupported) {
|
||||
return;
|
||||
}
|
||||
var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() {
|
||||
var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false;
|
||||
div.style.cssText = "position:absolute;font-size:1em;width:1em";
|
||||
if (!body) {
|
||||
body = fakeUsed = doc.createElement("body");
|
||||
body.style.background = "none";
|
||||
}
|
||||
docElem.style.fontSize = "100%";
|
||||
body.style.fontSize = "100%";
|
||||
body.appendChild(div);
|
||||
if (fakeUsed) {
|
||||
docElem.insertBefore(body, docElem.firstChild);
|
||||
}
|
||||
ret = div.offsetWidth;
|
||||
if (fakeUsed) {
|
||||
docElem.removeChild(body);
|
||||
} else {
|
||||
body.removeChild(div);
|
||||
}
|
||||
docElem.style.fontSize = originalHTMLFontSize;
|
||||
if (originalBodyFontSize) {
|
||||
body.style.fontSize = originalBodyFontSize;
|
||||
}
|
||||
ret = eminpx = parseFloat(ret);
|
||||
return ret;
|
||||
}, applyMedia = function(fromResize) {
|
||||
var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime();
|
||||
if (fromResize && lastCall && now - lastCall < resizeThrottle) {
|
||||
w.clearTimeout(resizeDefer);
|
||||
resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
|
||||
return;
|
||||
} else {
|
||||
lastCall = now;
|
||||
}
|
||||
for (var i in mediastyles) {
|
||||
if (mediastyles.hasOwnProperty(i)) {
|
||||
var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
|
||||
if (!!min) {
|
||||
min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
|
||||
}
|
||||
if (!!max) {
|
||||
max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
|
||||
}
|
||||
if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
|
||||
if (!styleBlocks[thisstyle.media]) {
|
||||
styleBlocks[thisstyle.media] = [];
|
||||
}
|
||||
styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var j in appendedEls) {
|
||||
if (appendedEls.hasOwnProperty(j)) {
|
||||
if (appendedEls[j] && appendedEls[j].parentNode === head) {
|
||||
head.removeChild(appendedEls[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
appendedEls.length = 0;
|
||||
for (var k in styleBlocks) {
|
||||
if (styleBlocks.hasOwnProperty(k)) {
|
||||
var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
|
||||
ss.type = "text/css";
|
||||
ss.media = k;
|
||||
head.insertBefore(ss, lastLink.nextSibling);
|
||||
if (ss.styleSheet) {
|
||||
ss.styleSheet.cssText = css;
|
||||
} else {
|
||||
ss.appendChild(doc.createTextNode(css));
|
||||
}
|
||||
appendedEls.push(ss);
|
||||
}
|
||||
}
|
||||
}, translate = function(styles, href, media) {
|
||||
var qs = styles.replace(respond.regex.comments, "").replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
|
||||
href = href.substring(0, href.lastIndexOf("/"));
|
||||
var repUrls = function(css) {
|
||||
return css.replace(respond.regex.urls, "$1" + href + "$2$3");
|
||||
}, useMedia = !ql && media;
|
||||
if (href.length) {
|
||||
href += "/";
|
||||
}
|
||||
if (useMedia) {
|
||||
ql = 1;
|
||||
}
|
||||
for (var i = 0; i < ql; i++) {
|
||||
var fullq, thisq, eachq, eql;
|
||||
if (useMedia) {
|
||||
fullq = media;
|
||||
rules.push(repUrls(styles));
|
||||
} else {
|
||||
fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
|
||||
rules.push(RegExp.$2 && repUrls(RegExp.$2));
|
||||
}
|
||||
eachq = fullq.split(",");
|
||||
eql = eachq.length;
|
||||
for (var j = 0; j < eql; j++) {
|
||||
thisq = eachq[j];
|
||||
if (isUnsupportedMediaQuery(thisq)) {
|
||||
continue;
|
||||
}
|
||||
mediastyles.push({
|
||||
media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
|
||||
rules: rules.length - 1,
|
||||
hasquery: thisq.indexOf("(") > -1,
|
||||
minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
|
||||
maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
|
||||
});
|
||||
}
|
||||
}
|
||||
applyMedia();
|
||||
}, makeRequests = function() {
|
||||
if (requestQueue.length) {
|
||||
var thisRequest = requestQueue.shift();
|
||||
ajax(thisRequest.href, function(styles) {
|
||||
translate(styles, thisRequest.href, thisRequest.media);
|
||||
parsedSheets[thisRequest.href] = true;
|
||||
w.setTimeout(function() {
|
||||
makeRequests();
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
}, ripCSS = function() {
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
|
||||
if (!!href && isCSS && !parsedSheets[href]) {
|
||||
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
|
||||
translate(sheet.styleSheet.rawCssText, href, media);
|
||||
parsedSheets[href] = true;
|
||||
} else {
|
||||
if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) {
|
||||
if (href.substring(0, 2) === "//") {
|
||||
href = w.location.protocol + href;
|
||||
}
|
||||
requestQueue.push({
|
||||
href: href,
|
||||
media: media
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
makeRequests();
|
||||
};
|
||||
ripCSS();
|
||||
respond.update = ripCSS;
|
||||
respond.getEmValue = getEmValue;
|
||||
function callMedia() {
|
||||
applyMedia(true);
|
||||
}
|
||||
if (w.addEventListener) {
|
||||
w.addEventListener("resize", callMedia, false);
|
||||
} else if (w.attachEvent) {
|
||||
w.attachEvent("onresize", callMedia);
|
||||
}
|
||||
})(this);
|
41
admin/src/scss/install.scss
Normal file
41
admin/src/scss/install.scss
Normal file
@ -0,0 +1,41 @@
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
details {
|
||||
summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
.message {
|
||||
form > & {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.fade {
|
||||
display: block;
|
||||
animation: fadein .5s linear;
|
||||
}
|
||||
|
||||
*:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 8px;
|
||||
|
||||
button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
button:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -179,68 +179,6 @@ a.button:hover, a.balloon-button:hover {
|
||||
/** 增加配置面板内部的错误样式 by 70 */
|
||||
|
||||
|
||||
/**
|
||||
* 安装样式
|
||||
*
|
||||
* @author mingcheng
|
||||
* @date 2008-09-06
|
||||
*/
|
||||
|
||||
/**
|
||||
* 安装向导
|
||||
*/
|
||||
.typecho-install {
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
.typecho-install-patch {
|
||||
margin-bottom: 2em;
|
||||
padding: 2em 0;
|
||||
background-color: #292D33;
|
||||
color: #FFF;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.typecho-install-patch ol {
|
||||
list-style: none;
|
||||
margin: 3em 0 1em;
|
||||
padding: 0;
|
||||
color: #999;
|
||||
}
|
||||
.typecho-install-patch li {
|
||||
display: inline-block;
|
||||
margin: 0 .8em;
|
||||
}
|
||||
.typecho-install-patch span {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
border: 2px solid #999;
|
||||
text-align: center;
|
||||
border-radius: 2em;
|
||||
}
|
||||
.typecho-install-patch li.current {
|
||||
color: #FFF;
|
||||
font-weight: bold;
|
||||
}
|
||||
.typecho-install-patch li.current span {
|
||||
border-color: #FFF;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 安装主体内容
|
||||
*/
|
||||
|
||||
.typecho-install .typecho-install-body input {
|
||||
width: 100%;
|
||||
}
|
||||
.typecho-install-body .typecho-option li {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 欢迎界面
|
||||
*/
|
||||
|
824
install.php
824
install.php
@ -29,17 +29,7 @@ Typecho_Common::init();
|
||||
else:
|
||||
|
||||
require_once dirname(__FILE__) . '/config.inc.php';
|
||||
|
||||
//判断是否已经安装
|
||||
$db = Typecho_Db::get();
|
||||
try {
|
||||
$installed = $db->fetchRow($db->select()->from('table.options')->where('name = ?', 'installed'));
|
||||
if (empty($installed) || $installed['value'] == 1) {
|
||||
exit(1);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// do nothing
|
||||
}
|
||||
$installDb = Typecho_Db::get();
|
||||
|
||||
endif;
|
||||
|
||||
@ -210,6 +200,28 @@ function install_get_db_drivers(): array {
|
||||
return $drivers;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current db driver
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function install_get_current_db_driver(): string {
|
||||
global $installDb;
|
||||
|
||||
if (empty($installDb)) {
|
||||
$driver = Typecho_Request::getInstance()->get('driver');
|
||||
$drivers = install_get_db_drivers();
|
||||
|
||||
if (empty($driver) || !isset($drivers[$driver])) {
|
||||
return key($drivers);
|
||||
}
|
||||
|
||||
return $driver;
|
||||
} else {
|
||||
return $installDb->getAdapterName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generate config file
|
||||
*
|
||||
@ -219,6 +231,8 @@ function install_get_db_drivers(): array {
|
||||
* @return string
|
||||
*/
|
||||
function install_config_file(string $adapter, string $dbPrefix, array $dbConfig): string {
|
||||
global $configWritten;
|
||||
|
||||
$lines = array_slice(file(__FILE__), 1, 26);
|
||||
$lines[] = "
|
||||
/** 定义数据库参数 */
|
||||
@ -226,7 +240,57 @@ function install_config_file(string $adapter, string $dbPrefix, array $dbConfig)
|
||||
\$db->addServer(" . (var_export($dbConfig, true)) . ", Typecho_Db::READ | Typecho_Db::WRITE);
|
||||
Typecho_Db::set(\$db);
|
||||
";
|
||||
return implode('', $lines);
|
||||
|
||||
$code = implode('', $lines);
|
||||
$configWritten = @file_put_contents(__TYPECHO_ROOT_DIR__ . '/config.inc.php', $code) !== false;
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove config file if written
|
||||
*/
|
||||
function install_remove_config_file() {
|
||||
global $configWritten;
|
||||
|
||||
if ($configWritten) {
|
||||
unlink(__TYPECHO_ROOT_DIR__ . '/config.inc.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check install
|
||||
*
|
||||
* @param string $type
|
||||
* @return bool
|
||||
*/
|
||||
function install_check(string $type): bool {
|
||||
switch ($type) {
|
||||
case 'config':
|
||||
return file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php');
|
||||
case 'db_structure':
|
||||
case 'db_data':
|
||||
global $installDb;
|
||||
|
||||
if (empty($installDb)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// check if table exists
|
||||
$values = $installDb->fetchAll($installDb->select()->from('table.options')
|
||||
->where('user = 0'));
|
||||
|
||||
if ($type == 'db_data' && empty($values)) {
|
||||
return false;
|
||||
}
|
||||
} catch (Typecho_Db_Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,23 +300,20 @@ Typecho_Db::set(\$db);
|
||||
* @param mixed $config
|
||||
*/
|
||||
function install_raise_error($error, $config = null) {
|
||||
$lines = [];
|
||||
|
||||
if (is_array($error)) {
|
||||
foreach ($error as $key => $value) {
|
||||
$lines[] = $key . ': ' . $value;
|
||||
}
|
||||
} else {
|
||||
$lines[] = $error;
|
||||
}
|
||||
|
||||
if (install_is_cli()) {
|
||||
echo implode("\n", $lines);
|
||||
if (is_array($error)) {
|
||||
foreach ($error as $key => $value) {
|
||||
echo (is_int($key) ? '' : $key . ': ') . $value;
|
||||
}
|
||||
} else {
|
||||
echo $error;
|
||||
}
|
||||
|
||||
exit(1);
|
||||
} else {
|
||||
Typecho_Response::getInstance()->throwJson([
|
||||
'success' => 0,
|
||||
'message' => implode("<br>", $lines),
|
||||
'message' => is_string($error) ? nl2br($error) : $error,
|
||||
'config' => $config
|
||||
]);
|
||||
}
|
||||
@ -260,60 +321,124 @@ function install_raise_error($error, $config = null) {
|
||||
|
||||
/**
|
||||
* @param $step
|
||||
* @param array|null $config
|
||||
*/
|
||||
function install_success($step) {
|
||||
function install_success($step, ?array $config = null) {
|
||||
if (install_is_cli()) {
|
||||
$method = 'install_step_' . $step . '_perform';
|
||||
$method();
|
||||
if ($step > 0) {
|
||||
$method = 'install_step_' . $step . '_perform';
|
||||
$method();
|
||||
}
|
||||
|
||||
if (!empty($config)) {
|
||||
echo implode("\n", $config);
|
||||
}
|
||||
} else {
|
||||
Typecho_Response::getInstance()->throwJson([
|
||||
'success' => $step
|
||||
'success' => 1,
|
||||
'message' => $step,
|
||||
'config' => $config
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function install_ajax_support() {
|
||||
?>
|
||||
<script>
|
||||
let form = document.querySelector('form'), errorBox = document.createElement('div');
|
||||
form.insertBefore(errorBox, form.firstChild);
|
||||
$options = Typecho_Widget::widget('Widget_Options');
|
||||
|
||||
errorBox.classList.add('error', 'hidden');
|
||||
?>
|
||||
<div id="success" class="hidden">
|
||||
<h2><?php _e('安装成功'); ?></h2>
|
||||
<p class="keep-word">
|
||||
<?php _e('您选择了使用原有的数据, 您的用户名和密码和原来的一致'); ?>
|
||||
</p>
|
||||
<p class="fresh-word">
|
||||
<?php _e('您的用户名是'); ?>: <strong id="success-user"></strong><br>
|
||||
<?php _e('您的密码是'); ?>: <strong id="success-password"></strong>
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="<?php $options->loginUrl(); ?>"><?php _e('点击这里访问您的控制面板'); ?></a></li>
|
||||
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('点击这里查看您的 Blog'); ?></a></li>
|
||||
</ul>
|
||||
<p><?php _e('希望您能尽情享用 Typecho 带来的乐趣!'); ?></p>
|
||||
</div>
|
||||
<script>
|
||||
let form = document.querySelector('form'), errorBox = document.createElement('div');
|
||||
|
||||
function showError(error) {
|
||||
let str = '<?php _t('安装程序捕捉到以下错误: " %s ". 程序被终止, 请检查您的配置信息.', '%') ?>';
|
||||
errorBox.innerHTML = str.replace('%', error);
|
||||
form.insertBefore(errorBox, form.firstChild);
|
||||
errorBox.classList.add('message', 'error');
|
||||
|
||||
errorBox.classList.remove('hidden');
|
||||
|
||||
return errorBox;
|
||||
}
|
||||
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
errorBox.classList.add('hidden');
|
||||
|
||||
fetch(this.getAttribute('action'), {
|
||||
method: 'POST',
|
||||
body: new FormData(this)
|
||||
}).then(function (response) {
|
||||
return response.json();
|
||||
}).then(function (data) {
|
||||
if (data.success) {
|
||||
location.href = '?step=' + data.message;
|
||||
function showError(error) {
|
||||
if (typeof error == 'string') {
|
||||
window.scrollTo({ top: 0 });
|
||||
errorBox.innerHTML = error;
|
||||
errorBox.classList.add('fade');
|
||||
} else {
|
||||
showError(data.message);
|
||||
}
|
||||
}).catch(function (error) {
|
||||
let el = showError(error.message);
|
||||
for (let k in error) {
|
||||
let input = document.querySelector('#' + k), msg = error[k], p = document.createElement('p');
|
||||
|
||||
if (typeof configError == 'function' && error.config) {
|
||||
configError(error.config, el);
|
||||
p.classList.add('message', 'error');
|
||||
p.innerHTML = msg;
|
||||
|
||||
input.parentNode.insertBefore(p, input.nextSibling);
|
||||
|
||||
input.addEventListener('input', function () {
|
||||
p.remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, true);
|
||||
</script>
|
||||
|
||||
return errorBox;
|
||||
}
|
||||
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
errorBox.classList.remove('fade');
|
||||
form.querySelectorAll('button').forEach(function (btn) {
|
||||
btn.setAttribute('disabled', 'disabled');
|
||||
});
|
||||
|
||||
form.querySelectorAll('.typecho-option .error').forEach(function (el) {
|
||||
el.remove();
|
||||
});
|
||||
|
||||
fetch(this.getAttribute('action'), {
|
||||
method: 'POST',
|
||||
body: new FormData(this)
|
||||
}).then(function (response) {
|
||||
return response.json();
|
||||
}).then(function (data) {
|
||||
form.querySelectorAll('button').forEach(function (btn) {
|
||||
btn.removeAttribute('disabled');
|
||||
});
|
||||
|
||||
if (data.success) {
|
||||
if (data.message) {
|
||||
location.href = '?step=' + data.message;
|
||||
} else {
|
||||
let success = document.querySelector('#success');
|
||||
|
||||
form.classList.add('hidden');
|
||||
success.classList.remove('hidden');
|
||||
|
||||
if (data.config) {
|
||||
success.classList.add('fresh');
|
||||
} else {
|
||||
success.classList.add('keep');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let el = showError(data.message);
|
||||
|
||||
if (typeof configError == 'function' && data.config) {
|
||||
configError(data.config, el);
|
||||
}
|
||||
}
|
||||
}).catch(function (error) {
|
||||
showError(error.message);
|
||||
});
|
||||
}, true);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
@ -321,92 +446,168 @@ function install_step_1() {
|
||||
$langs = Widget_Options_General::getLangs();
|
||||
$lang = install_get_lang();
|
||||
?>
|
||||
<form method="get" action="?step=2">
|
||||
<h1><?php _e('欢迎使用 Typecho'); ?></h1>
|
||||
<h2><?php _e('安装说明'); ?></h2>
|
||||
<p><strong><?php _e('本安装程序将自动检测服务器环境是否符合最低配置需求. 如果不符合, 将在上方出现提示信息, 请按照提示信息检查您的主机配置. 如果服务器环境符合要求, 将在下方出现 "开始下一步" 的按钮, 点击此按钮即可一步完成安装.'); ?></strong></p>
|
||||
<h2><?php _e('许可及协议'); ?></h2>
|
||||
<p><?php _e('Typecho 基于 <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> 协议发布, 我们允许用户在 GPL 协议许可的范围内使用, 拷贝, 修改和分发此程序.'); ?>
|
||||
<?php _e('在GPL许可的范围内, 您可以自由地将其用于商业以及非商业用途.'); ?></p>
|
||||
<p><?php _e('Typecho 软件由其社区提供支持, 核心开发团队负责维护程序日常开发工作以及新特性的制定.'); ?>
|
||||
<?php _e('如果您遇到使用上的问题, 程序中的 BUG, 以及期许的新功能, 欢迎您在社区中交流或者直接向我们贡献代码.'); ?>
|
||||
<?php _e('对于贡献突出者, 他的名字将出现在贡献者名单中.'); ?></p>
|
||||
<p class="submit">
|
||||
<button type="submit"><?php _e('我准备好了, 开始下一步 »'); ?></button>
|
||||
<div class="row typecho-page-main">
|
||||
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
|
||||
<div class="typecho-page-title">
|
||||
<h2><?php _e('欢迎使用 Typecho'); ?></h2>
|
||||
</div>
|
||||
<div id="typecho-welcome">
|
||||
<form method="get" action="install.php">
|
||||
<h3><?php _e('安装说明'); ?></h3>
|
||||
<ul>
|
||||
<li class="warning"><strong><?php _e('本安装程序将自动检测服务器环境是否符合最低配置需求. 如果不符合, 将在上方出现提示信息, 请按照提示信息检查您的主机配置. 如果服务器环境符合要求, 将在下方出现 "开始下一步" 的按钮, 点击此按钮即可一步完成安装.'); ?></strong></li>
|
||||
</ul>
|
||||
<h3><?php _e('许可及协议'); ?></h3>
|
||||
<ul>
|
||||
<li><?php _e('Typecho 基于 <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> 协议发布, 我们允许用户在 GPL 协议许可的范围内使用, 拷贝, 修改和分发此程序.'); ?>
|
||||
<?php _e('在GPL许可的范围内, 您可以自由地将其用于商业以及非商业用途.'); ?></li>
|
||||
<li><?php _e('Typecho 软件由其社区提供支持, 核心开发团队负责维护程序日常开发工作以及新特性的制定.'); ?>
|
||||
<?php _e('如果您遇到使用上的问题, 程序中的 BUG, 以及期许的新功能, 欢迎您在社区中交流或者直接向我们贡献代码.'); ?>
|
||||
<?php _e('对于贡献突出者, 他的名字将出现在贡献者名单中.'); ?></li>
|
||||
</ul>
|
||||
|
||||
<?php if (count($langs) > 1): ?>
|
||||
<select style="float: right" onchange="location.href='?lang=' + this.value">
|
||||
<?php foreach ($langs as $key => $val): ?>
|
||||
<option value="<?php echo $key; ?>"<?php if ($lang == $key): ?> selected<?php endif; ?>><?php echo $val; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</form>
|
||||
<p class="submit">
|
||||
<button class="btn primary" type="submit"><?php _e('我准备好了, 开始下一步 »'); ?></button>
|
||||
<input type="hidden" name="step" value="2">
|
||||
|
||||
<?php if (count($langs) > 1): ?>
|
||||
<select style="float: right" onchange="location.href='?lang=' + this.value">
|
||||
<?php foreach ($langs as $key => $val): ?>
|
||||
<option value="<?php echo $key; ?>"<?php if ($lang == $key): ?> selected<?php endif; ?>><?php echo $val; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* check step 2
|
||||
*/
|
||||
function install_step_2_check(): bool {
|
||||
return !file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* display step 2
|
||||
*/
|
||||
function install_step_2() {
|
||||
global $installDb;
|
||||
|
||||
$drivers = install_get_db_drivers();
|
||||
$adapter = Typecho_Request::getInstance()->get('driver', key($drivers));
|
||||
$adapter = install_get_current_db_driver();
|
||||
$type = install_get_db_type($adapter);
|
||||
?>
|
||||
<form action="?step=2" method="post">
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label for="dbAdapter" class="typecho-label"><?php _e('数据库适配器'); ?></label>
|
||||
<select name="dbAdapter" id="dbAdapter" onchange="location.href='?step=2&driver=' + this.value">
|
||||
<?php foreach ($drivers as $driver => $name): ?>
|
||||
<option value="<?php echo $driver; ?>"<?php if($driver == $adapter): ?> selected="selected"<?php endif; ?>><?php echo $name; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="description"><?php _e('请根据您的数据库类型选择合适的适配器'); ?></p>
|
||||
<input type="hidden" id="dbNext" name="dbNext" value="none">
|
||||
</li>
|
||||
<?php require_once './install/' . $type . '.php'; ?>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPrefix"><?php _e('数据库前缀'); ?></label>
|
||||
<input type="text" class="text" name="dbPrefix" id="dbPrefix" value="<?php _v('dbPrefix', 'typecho_'); ?>" />
|
||||
<p class="description"><?php _e('默认前缀是 "typecho_"'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
<script>
|
||||
function configError(config, errorBox) {
|
||||
let next = document.querySelector('#dbNext'),
|
||||
line = document.createElement('p'),
|
||||
form = document.querySelector('form');
|
||||
|
||||
errorBox.appendChild(line);
|
||||
|
||||
config.forEach(function (word, key) {
|
||||
let btn = document.createElement('button');
|
||||
|
||||
btn.innerHTML = word;
|
||||
btn.addEventListener('click', function () {
|
||||
next.setAttribute('value', key);
|
||||
});
|
||||
|
||||
line.appendChild(btn);
|
||||
form.submit();
|
||||
});
|
||||
if (!empty($installDb)) {
|
||||
$config = $installDb->getConfig(Typecho_Db::WRITE)->toArray();
|
||||
$config['prefix'] = $installDb->getPrefix();
|
||||
$config['adapter'] = $adapter;
|
||||
}
|
||||
</script>
|
||||
?>
|
||||
<div class="row typecho-page-main">
|
||||
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
|
||||
<div class="typecho-page-title">
|
||||
<h2><?php _e('初始化配置'); ?></h2>
|
||||
</div>
|
||||
<form action="install.php" method="post">
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label for="dbAdapter" class="typecho-label"><?php _e('数据库适配器'); ?></label>
|
||||
<select name="dbAdapter" id="dbAdapter" onchange="location.href='?step=2&driver=' + this.value">
|
||||
<?php foreach ($drivers as $driver => $name): ?>
|
||||
<option value="<?php echo $driver; ?>"<?php if($driver == $adapter): ?> selected="selected"<?php endif; ?>><?php echo $name; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="description"><?php _e('请根据您的数据库类型选择合适的适配器'); ?></p>
|
||||
<input type="hidden" id="dbNext" name="dbNext" value="none">
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPrefix"><?php _e('数据库前缀'); ?></label>
|
||||
<input type="text" class="text" name="dbPrefix" id="dbPrefix" value="<?php _v('dbPrefix', 'typecho_'); ?>" />
|
||||
<p class="description"><?php _e('默认前缀是 "typecho_"'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
<?php require_once './install/' . $type . '.php'; ?>
|
||||
|
||||
|
||||
<ul class="typecho-option typecho-option-submit">
|
||||
<li>
|
||||
<button type="submit" class="btn primary"><?php _e('确认, 开始安装 »'); ?></button>
|
||||
<input type="hidden" name="step" value="2">
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function configError(config, errorBox) {
|
||||
let next = document.querySelector('#dbNext'),
|
||||
line = document.createElement('p'),
|
||||
form = document.querySelector('form');
|
||||
|
||||
if (config.code) {
|
||||
let text = document.createElement('textarea');
|
||||
text.value = config.code;
|
||||
text.setAttribute('readonly', 'readonly');
|
||||
|
||||
errorBox.appendChild(text);
|
||||
return;
|
||||
}
|
||||
|
||||
errorBox.appendChild(line);
|
||||
|
||||
for (let key in config) {
|
||||
let word = config[key],
|
||||
btn = document.createElement('button');
|
||||
|
||||
btn.innerHTML = word;
|
||||
btn.setAttribute('type', 'button');
|
||||
btn.classList.add('btn', 'btn-s', 'primary');
|
||||
|
||||
btn.addEventListener('click', function () {
|
||||
next.value = key;
|
||||
form.dispatchEvent(new Event('submit'));
|
||||
});
|
||||
|
||||
line.appendChild(btn);
|
||||
}
|
||||
}
|
||||
|
||||
<?php if (!empty($config)): ?>
|
||||
function fillInput(config) {
|
||||
for (let k in config) {
|
||||
let value = config[k],
|
||||
key = 'db' + k.charAt(0).toUpperCase() + k.slice(1),
|
||||
input = document.querySelector('#' + key);
|
||||
|
||||
input.value = value;
|
||||
|
||||
if (input.children.length > 0) {
|
||||
for (let i = 0; i < input.children.length; i ++) {
|
||||
let option = input.children[i];
|
||||
|
||||
if (!option.selected) {
|
||||
option.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input.setAttribute('readonly', 'readonly');
|
||||
}
|
||||
}
|
||||
|
||||
fillInput(<?php echo Json::encode($config); ?>);
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
<?php
|
||||
install_ajax_support();
|
||||
}
|
||||
|
||||
/**
|
||||
* perform install step 2
|
||||
*/
|
||||
function install_step_2_perform() {
|
||||
global $installDb;
|
||||
|
||||
$request = Typecho_Request::getInstance();
|
||||
$drivers = install_get_db_drivers();
|
||||
|
||||
@ -484,38 +685,37 @@ function install_step_2_perform() {
|
||||
$dbConfig = [];
|
||||
|
||||
foreach ($configMap[$type] as $key => $value) {
|
||||
$dbConfig[strtolower(substr($key, 2))]
|
||||
= $config[$key] === null ? (install_is_cli() ? $value : null) : $config[$key];
|
||||
$dbConfig[$key] = $config[$key] === null ? (install_is_cli() ? $value : null) : $config[$key];
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'Mysql':
|
||||
$error = (new Typecho_Validate())
|
||||
->addRule('host', 'required', _t('确认您的配置'))
|
||||
->addRule('port', 'required', _t('确认您的配置'))
|
||||
->addRule('port', 'isInteger', _t('确认您的配置'))
|
||||
->addRule('user', 'required', _t('确认您的配置'))
|
||||
->addRule('charset', 'required', _t('确认您的配置'))
|
||||
->addRule('charset', 'enum', _t('确认您的配置'), ['utf8', 'utf8mb4'])
|
||||
->addRule('database', 'required', _t('确认您的配置'))
|
||||
->addRule('engine', 'required', _t('确认您的配置'))
|
||||
->addRule('engine', 'enum', _t('确认您的配置'), ['InnoDB', 'MyISAM'])
|
||||
->addRule('dbHost', 'required', _t('确认您的配置'))
|
||||
->addRule('dbPort', 'required', _t('确认您的配置'))
|
||||
->addRule('dbPort', 'isInteger', _t('确认您的配置'))
|
||||
->addRule('dbUser', 'required', _t('确认您的配置'))
|
||||
->addRule('dbCharset', 'required', _t('确认您的配置'))
|
||||
->addRule('dbCharset', 'enum', _t('确认您的配置'), ['utf8', 'utf8mb4'])
|
||||
->addRule('dbDatabase', 'required', _t('确认您的配置'))
|
||||
->addRule('dbEngine', 'required', _t('确认您的配置'))
|
||||
->addRule('dbEngine', 'enum', _t('确认您的配置'), ['InnoDB', 'MyISAM'])
|
||||
->run($dbConfig);
|
||||
break;
|
||||
case 'Pgsql':
|
||||
$error = (new Typecho_Validate())
|
||||
->addRule('host', 'required', _t('确认您的配置'))
|
||||
->addRule('port', 'required', _t('确认您的配置'))
|
||||
->addRule('port', 'isInteger', _t('确认您的配置'))
|
||||
->addRule('user', 'required', _t('确认您的配置'))
|
||||
->addRule('charset', 'required', _t('确认您的配置'))
|
||||
->addRule('charset', 'enum', _t('确认您的配置'), ['utf8'])
|
||||
->addRule('database', 'required', _t('确认您的配置'))
|
||||
->addRule('dbHost', 'required', _t('确认您的配置'))
|
||||
->addRule('dbPort', 'required', _t('确认您的配置'))
|
||||
->addRule('dbPort', 'isInteger', _t('确认您的配置'))
|
||||
->addRule('dbUser', 'required', _t('确认您的配置'))
|
||||
->addRule('dbCharset', 'required', _t('确认您的配置'))
|
||||
->addRule('dbCharset', 'enum', _t('确认您的配置'), ['utf8'])
|
||||
->addRule('dbDatabase', 'required', _t('确认您的配置'))
|
||||
->run($dbConfig);
|
||||
break;
|
||||
case 'SQLite':
|
||||
$error = (new Typecho_Validate())
|
||||
->addRule('file', 'required', _t('确认您的配置'))
|
||||
->addRule('dbFile', 'required', _t('确认您的配置'))
|
||||
->run($dbConfig);
|
||||
break;
|
||||
default:
|
||||
@ -527,19 +727,32 @@ function install_step_2_perform() {
|
||||
install_raise_error($error);
|
||||
}
|
||||
|
||||
// detect db config
|
||||
try {
|
||||
$installDb = new Typecho_Db($config['dbAdapter'], $config['dbPrefix']);
|
||||
$installDb->addServer($dbConfig, Typecho_Db::READ | Typecho_Db::WRITE);
|
||||
$installDb->query('SELECT 1=1');
|
||||
} catch (Typecho_Db_Adapter_Exception $e) {
|
||||
install_raise_error(_t('对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装'));
|
||||
} catch (Typecho_Db_Exception $e) {
|
||||
install_raise_error(_t('安装程序捕捉到以下错误: " %s ". 程序被终止, 请检查您的配置信息.', $e->getMessage()));
|
||||
foreach ($dbConfig as $key => $value) {
|
||||
$dbConfig[strtolower(substr($key, 2))] = $value;
|
||||
}
|
||||
|
||||
if (!isset($installDb)) {
|
||||
return;
|
||||
if (empty($installDb)) {
|
||||
// detect db config
|
||||
try {
|
||||
$installDb = new Typecho_Db($config['dbAdapter'], $config['dbPrefix']);
|
||||
$installDb->addServer($dbConfig, Typecho_Db::READ | Typecho_Db::WRITE);
|
||||
$installDb->query('SELECT 1=1');
|
||||
} catch (Typecho_Db_Adapter_Exception $e) {
|
||||
install_raise_error(_t('对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装'));
|
||||
} catch (Typecho_Db_Exception $e) {
|
||||
install_raise_error(_t('安装程序捕捉到以下错误: " %s ". 程序被终止, 请检查您的配置信息.', $e->getMessage()));
|
||||
}
|
||||
|
||||
$code = install_config_file($config['dbAdapter'], $config['dbPrefix'], $dbConfig);
|
||||
|
||||
if (!install_check('config')) {
|
||||
install_raise_error(
|
||||
_t('安装程序无法自动创建 <strong>config.inc.php</strong> 文件') . "\n" .
|
||||
_t('您可以在网站根目录下手动创建 <strong>config.inc.php</strong> 文件, 并复制如下代码至其中')
|
||||
, [
|
||||
'code' => $code
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// delete exists db
|
||||
@ -597,14 +810,22 @@ function install_step_2_perform() {
|
||||
('Pgsql' == $type && '42P07' == $code)) {
|
||||
|
||||
if ($config['dbNext'] == 'keep') {
|
||||
install_success(3);
|
||||
} elseif ($config['dbNext' == 'none']) {
|
||||
if (install_check('db_data')) {
|
||||
install_success(0);
|
||||
} else {
|
||||
install_success(3);
|
||||
}
|
||||
} elseif ($config['dbNext'] == 'none') {
|
||||
install_remove_config_file();
|
||||
|
||||
install_raise_error(_t('安装程序检查到原有数据表已经存在.'), [
|
||||
'delete' => _t('删除原有数据'),
|
||||
'keep' => _t('使用原有数据')
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
install_remove_config_file();
|
||||
|
||||
install_raise_error(_t('安装程序捕捉到以下错误: "%s". 程序被终止, 请检查您的配置信息.', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
@ -612,8 +833,279 @@ function install_step_2_perform() {
|
||||
install_success(3);
|
||||
}
|
||||
|
||||
$options = Typecho_Widget::widget('Widget_Options', install_get_default_options());
|
||||
Typecho_Widget::widget('Widget_Init');
|
||||
/**
|
||||
* display step 3
|
||||
*/
|
||||
function install_step_3() {
|
||||
$options = Typecho_Widget::widget('Widget_Options');
|
||||
?>
|
||||
<div class="row typecho-page-main">
|
||||
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
|
||||
<div class="typecho-page-title">
|
||||
<h2><?php _e('创建您的管理员帐号'); ?></h2>
|
||||
</div>
|
||||
<form action="install.php" method="post">
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="userUrl"><?php _e('网站地址'); ?></label>
|
||||
<input type="text" name="userUrl" id="userUrl" class="text" value="<?php $options->siteUrl(); ?>" />
|
||||
<p class="description"><?php _e('这是程序自动匹配的网站路径, 如果不正确请修改它'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="userName"><?php _e('用户名'); ?></label>
|
||||
<input type="text" name="userName" id="userName" class="text" />
|
||||
<p class="description"><?php _e('请填写您的用户名'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="userPassword"><?php _e('登录密码'); ?></label>
|
||||
<input type="password" name="userPassword" id="userPassword" class="text" />
|
||||
<p class="description"><?php _e('请填写您的登录密码, 如果留空系统将为您随机生成一个'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="userMail"><?php _e('邮件地址'); ?></label>
|
||||
<input type="text" name="userMail" id="userMail" class="text" />
|
||||
<p class="description"><?php _e('请填写一个您的常用邮箱'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="typecho-option typecho-option-submit">
|
||||
<li>
|
||||
<button type="submit" class="btn primary"><?php _e('继续安装 »'); ?></button>
|
||||
<input type="hidden" name="step" value="3">
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
install_ajax_support();
|
||||
}
|
||||
|
||||
/**
|
||||
* perform step 3
|
||||
*/
|
||||
function install_step_3_perform() {
|
||||
global $installDb;
|
||||
|
||||
$request = Typecho_Request::getInstance();
|
||||
$defaultPassword = Typecho_Common::randString(8);
|
||||
$options = Typecho_Widget::widget('Widget_Options');
|
||||
|
||||
if (install_is_cli()) {
|
||||
$config = [
|
||||
'userUrl' => $request->getServer('TYPECHO_SITE_URL', 'http://localhost'),
|
||||
'userName' => $request->getServer('TYPECHO_USER_NAME', 'typecho'),
|
||||
'userPassword' => $request->getServer('TYPECHO_USER_PASSWORD'),
|
||||
'userMail' => $request->getServer('TYPECHO_USER_MAIL', 'admin@localhost')
|
||||
];
|
||||
} else {
|
||||
$config = $request->from([
|
||||
'userUrl',
|
||||
'userName',
|
||||
'userPassword',
|
||||
'userMail',
|
||||
]);
|
||||
}
|
||||
|
||||
$error = (new Typecho_Validate())
|
||||
->addRule('userUrl', 'required', _t('请填写您的网站地址'))
|
||||
->addRule('userUrl', 'url', _t('请填写您的网站地址'))
|
||||
->addRule('userName', 'required', _t('请填写您的用户名'))
|
||||
->addRule('userName', 'maxLength', _t('用户名长度超过限制, 请不要超过 32 个字符'), 32)
|
||||
->addRule('userMail', 'required', _t('请填写您的邮箱地址'))
|
||||
->addRule('userMail', 'email', _t('请填写您的邮箱地址'))
|
||||
->addRule('userMail', 'maxLength', _t('邮箱长度超过限制, 请不要超过 200 个字符'), 200)
|
||||
->run($config);
|
||||
|
||||
if (!empty($error)) {
|
||||
install_raise_error($error);
|
||||
}
|
||||
|
||||
if (empty($config['userPassword'])) {
|
||||
$config['userPassword'] = $defaultPassword;
|
||||
}
|
||||
|
||||
try {
|
||||
// write options
|
||||
foreach (install_get_default_options() as $key => $value) {
|
||||
$installDb->query(
|
||||
$installDb->insert('table.options')->rows(['name' => $key, 'user' => 0, 'value' => $value])
|
||||
);
|
||||
}
|
||||
|
||||
// write user
|
||||
$hasher = new PasswordHash(8, true);
|
||||
$installDb->query(
|
||||
$installDb->insert('table.users')->rows([
|
||||
'name' => $config['userName'],
|
||||
'password' => $hasher->HashPassword($config['userPassword']),
|
||||
'mail' => $config['userMail'],
|
||||
'url' => $options->siteUrl,
|
||||
'screenName' => $config['userName'],
|
||||
'group' => 'administrator',
|
||||
'created' => Typecho_Date::time()
|
||||
])
|
||||
);
|
||||
|
||||
// write category
|
||||
$installDb->query(
|
||||
$installDb->insert('table.metas')
|
||||
->rows([
|
||||
'name' => _t('默认分类'),
|
||||
'slug' => 'default',
|
||||
'type' => 'category',
|
||||
'description' => _t('只是一个默认分类')
|
||||
])
|
||||
);
|
||||
|
||||
$installDb->query($installDb->insert('table.relationships')->rows(['cid' => 1, 'mid' => 1]));
|
||||
|
||||
// write first page and post
|
||||
$installDb->query(
|
||||
$installDb->insert('table.contents')->rows([
|
||||
'title' => _t('欢迎使用 Typecho'),
|
||||
'slug' => 'start', 'created' => Typecho_Date::time(),
|
||||
'modified' => Typecho_Date::time(),
|
||||
'text' => '<!--markdown-->' . _t('如果您看到这篇文章,表示您的 blog 已经安装成功.'),
|
||||
'authorId' => 1,
|
||||
'type' => 'post',
|
||||
'status' => 'publish',
|
||||
'commentsNum' => 1,
|
||||
'allowComment' => 1,
|
||||
'allowPing' => 1,
|
||||
'allowFeed' => 1,
|
||||
'parent' => 0
|
||||
])
|
||||
);
|
||||
|
||||
$installDb->query(
|
||||
$installDb->insert('table.contents')->rows([
|
||||
'title' => _t('关于'),
|
||||
'slug' => 'start-page',
|
||||
'created' => Typecho_Date::time(),
|
||||
'modified' => Typecho_Date::time(),
|
||||
'text' => '<!--markdown-->' . _t('本页面由 Typecho 创建, 这只是个测试页面.'),
|
||||
'authorId' => 1,
|
||||
'order' => 0,
|
||||
'type' => 'page',
|
||||
'status' => 'publish',
|
||||
'commentsNum' => 0,
|
||||
'allowComment' => 1,
|
||||
'allowPing' => 1,
|
||||
'allowFeed' => 1,
|
||||
'parent' => 0
|
||||
])
|
||||
);
|
||||
|
||||
// write comment
|
||||
$installDb->query(
|
||||
$installDb->insert('table.comments')->rows([
|
||||
'cid' => 1, 'created' => Typecho_Date::time(),
|
||||
'author' => 'Typecho',
|
||||
'ownerId' => 1,
|
||||
'url' => 'http://typecho.org',
|
||||
'ip' => '127.0.0.1',
|
||||
'agent' => $options->generator,
|
||||
'text' => '欢迎加入 Typecho 大家族',
|
||||
'type' => 'comment',
|
||||
'status' => 'approved',
|
||||
'parent' => 0
|
||||
])
|
||||
);
|
||||
} catch (Typecho_Db_Exception $e) {
|
||||
install_raise_error($e->getMessage());
|
||||
}
|
||||
|
||||
install_success(0, [
|
||||
$config['userName'],
|
||||
$config['userPassword']
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatch install action
|
||||
*
|
||||
* @throws Typecho_Exception
|
||||
*/
|
||||
function install_dispatch() {
|
||||
// init default options
|
||||
$options = Typecho_Widget::widget('Widget_Options', install_get_default_options());
|
||||
Typecho_Widget::widget('Widget_Init');
|
||||
|
||||
// install finished yet
|
||||
if (
|
||||
install_check('config')
|
||||
&& install_check('db_structure')
|
||||
&& install_check('db_data')
|
||||
) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if (install_is_cli()) {
|
||||
install_step_2_perform();
|
||||
} else {
|
||||
$request = Typecho_Request::getInstance();
|
||||
$response = Typecho_Response::getInstance();
|
||||
$step = $request->get('step');
|
||||
|
||||
$action = 1;
|
||||
|
||||
switch (true) {
|
||||
case $step == 2:
|
||||
if (!install_check('db_structure')) {
|
||||
$action = 2;
|
||||
} else {
|
||||
$response->redirect('install.php?step=3');
|
||||
}
|
||||
break;
|
||||
case $step == 3:
|
||||
if (install_check('db_structure')) {
|
||||
$action = 3;
|
||||
} else {
|
||||
$response->redirect('install.php?step=2');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$method = 'install_step_' . $action;
|
||||
|
||||
if ($request->isPost() && $action > 1) {
|
||||
$method .= '_perform';
|
||||
$method();
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="<?php _e('UTF-8'); ?>" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<title><?php _e('Typecho 安装程序'); ?></title>
|
||||
<link rel="stylesheet" type="text/css" href="<?php $options->adminStaticUrl('css', 'normalize.css') ?>" />
|
||||
<link rel="stylesheet" type="text/css" href="<?php $options->adminStaticUrl('css', 'grid.css') ?>" />
|
||||
<link rel="stylesheet" type="text/css" href="<?php $options->adminStaticUrl('css', 'style.css') ?>" />
|
||||
<link rel="stylesheet" type="text/css" href="<?php $options->adminStaticUrl('css', 'install.css') ?>" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="body container">
|
||||
<h1><a href="http://typecho.org" target="_blank" class="i-logo">Typecho</a></h1>
|
||||
<?php $method(); ?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
install_dispatch();
|
||||
exit;
|
||||
|
||||
// 挡掉可能的跨站请求
|
||||
if (!empty($_GET) || !empty($_POST)) {
|
||||
|
@ -1,43 +1,66 @@
|
||||
<?php if(!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
|
||||
<li>
|
||||
<label class="typecho-label" for="dbHost"><?php _e('数据库地址'); ?></label>
|
||||
<input type="text" class="text" name="dbHost" id="dbHost" value="localhost"/>
|
||||
<p class="description"><?php _e('您可能会使用 "%s"', 'localhost'); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
|
||||
<input type="text" class="text" name="dbPort" id="dbPort" value="3306"/>
|
||||
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbUser"><?php _e('数据库用户名'); ?></label>
|
||||
<input type="text" class="text" name="dbUser" id="dbUser" value="" />
|
||||
<p class="description"><?php _e('您可能会使用 "%s"', 'root'); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPassword"><?php _e('数据库密码'); ?></label>
|
||||
<input type="password" class="text" name="dbPassword" id="dbPassword" value="" />
|
||||
</li>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbDatabase"><?php _e('数据库名'); ?></label>
|
||||
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="" />
|
||||
<p class="description"><?php _e('请您指定数据库名称'); ?></p>
|
||||
</li>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbHost"><?php _e('数据库地址'); ?></label>
|
||||
<input type="text" class="text" name="dbHost" id="dbHost" value="localhost"/>
|
||||
<p class="description"><?php _e('您可能会使用 "%s"', 'localhost'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<li>
|
||||
<label class="typecho-label" for="dbCharset"><?php _e('数据库编码'); ?></label>
|
||||
<select name="dbCharset" id="dbCharset">
|
||||
<option value="utf8mb4">utf8mb4</option>
|
||||
<option value="utf8">utf8</option>
|
||||
</select>
|
||||
<p class="description"><?php _e('选择 utf8mb4 编码至少需要 MySQL 5.5.3 版本'); ?></p>
|
||||
</li>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbUser"><?php _e('数据库用户名'); ?></label>
|
||||
<input type="text" class="text" name="dbUser" id="dbUser" value="" />
|
||||
<p class="description"><?php _e('您可能会使用 "%s"', 'root'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<li>
|
||||
<label class="typecho-label" for="dbEngine"><?php _e('数据库引擎'); ?></label>
|
||||
<select name="dbEngine" id="dbEngine">
|
||||
<option value="InnoDB">InnoDB</option>
|
||||
<option value="MyISAM">MyISAM</option>
|
||||
</select>
|
||||
</li>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPassword"><?php _e('数据库密码'); ?></label>
|
||||
<input type="password" class="text" name="dbPassword" id="dbPassword" value="" />
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbDatabase"><?php _e('数据库名'); ?></label>
|
||||
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="" />
|
||||
<p class="description"><?php _e('请您指定数据库名称'); ?></p>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<strong><?php _e('高级选项'); ?></strong>
|
||||
</summary>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
|
||||
<input type="text" class="text" name="dbPort" id="dbPort" value="3306"/>
|
||||
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbCharset"><?php _e('数据库编码'); ?></label>
|
||||
<select name="dbCharset" id="dbCharset">
|
||||
<option value="utf8mb4">utf8mb4</option>
|
||||
<option value="utf8">utf8</option>
|
||||
</select>
|
||||
<p class="description"><?php _e('选择 utf8mb4 编码至少需要 MySQL 5.5.3 版本'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbEngine"><?php _e('数据库引擎'); ?></label>
|
||||
<select name="dbEngine" id="dbEngine">
|
||||
<option value="InnoDB">InnoDB</option>
|
||||
<option value="MyISAM">MyISAM</option>
|
||||
</select>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
@ -1,26 +1,37 @@
|
||||
<?php if(!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbHost"><?php _e('数据库地址'); ?></label>
|
||||
<input type="text" class="text" name="dbHost" id="dbHost" value="localhost"/>
|
||||
<p class="description"><?php _e('您可能会使用 "%s"', 'localhost'); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
|
||||
<input type="text" class="text" name="dbPort" id="dbPort" value="5432"/>
|
||||
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbUser"><?php _e('数据库用户名'); ?></label>
|
||||
<input type="text" class="text" name="dbUser" id="dbUser" value="postgres" />
|
||||
<p class="description"><?php _e('您可能会使用 "%s"', 'postgres'); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPassword"><?php _e('数据库密码'); ?></label>
|
||||
<input type="password" class="text" name="dbPassword" id="dbPassword" value="" />
|
||||
</li>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbDatabase"><?php _e('数据库名'); ?></label>
|
||||
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="" />
|
||||
<p class="description"><?php _e('请您指定数据库名称'); ?></p>
|
||||
</li>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbHost"><?php _e('数据库地址'); ?></label>
|
||||
<input type="text" class="text" name="dbHost" id="dbHost" value="localhost"/>
|
||||
<p class="description"><?php _e('您可能会使用 "%s"', 'localhost'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
|
||||
<input type="text" class="text" name="dbPort" id="dbPort" value="5432"/>
|
||||
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbUser"><?php _e('数据库用户名'); ?></label>
|
||||
<input type="text" class="text" name="dbUser" id="dbUser" value="postgres" />
|
||||
<p class="description"><?php _e('您可能会使用 "%s"', 'postgres'); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbPassword"><?php _e('数据库密码'); ?></label>
|
||||
<input type="password" class="text" name="dbPassword" id="dbPassword" value="" />
|
||||
</li
|
||||
</ul>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbDatabase"><?php _e('数据库名'); ?></label>
|
||||
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="" />
|
||||
<p class="description"><?php _e('请您指定数据库名称'); ?></p>
|
||||
</li
|
||||
</ul>
|
||||
|
||||
<input type="hidden" name="dbCharset" value="utf8" />
|
||||
|
@ -1,7 +1,9 @@
|
||||
<?php if(!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
<?php $defaultDir = __TYPECHO_ROOT_DIR__ . '/usr/' . uniqid() . '.db'; ?>
|
||||
<li>
|
||||
<label class="typecho-label" for="dbFile"><?php _e('数据库文件路径'); ?></label>
|
||||
<input type="text" class="text" name="dbFile" id="dbFile" value="<?php echo $defaultDir; ?>"/>
|
||||
<p class="description"><?php _e('"%s" 是我们为您自动生成的地址', $defaultDir); ?></p>
|
||||
</li>
|
||||
<ul class="typecho-option">
|
||||
<li>
|
||||
<label class="typecho-label" for="dbFile"><?php _e('数据库文件路径'); ?></label>
|
||||
<input type="text" class="text" name="dbFile" id="dbFile" value="<?php echo $defaultDir; ?>"/>
|
||||
<p class="description"><?php _e('"%s" 是我们为您自动生成的地址', $defaultDir); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
6179
tools/package-lock.json
generated
6179
tools/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,7 @@
|
||||
"license": "GPL-2.0-only",
|
||||
"dependencies": {
|
||||
"chalk": "^4.0.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"node-sass": "^4.14.1",
|
||||
"sprite-magic-importer": "^1.6.2",
|
||||
"uglify-js": "^3.11.6"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
<!DOCTYPE HTML>
|
||||
<html class="no-js">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="<?php $this->options->charset(); ?>">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
@ -981,7 +981,11 @@ EOF;
|
||||
public static function url($path, $prefix)
|
||||
{
|
||||
$path = (0 === strpos($path, './')) ? substr($path, 2) : $path;
|
||||
return rtrim($prefix, '/') . '/' . str_replace('//', '/', ltrim($path, '/'));
|
||||
return rtrim(
|
||||
rtrim($prefix, '/') . '/'
|
||||
. str_replace('//', '/', ltrim($path, '/')),
|
||||
'/'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,7 @@ class Typecho_Config implements Iterator
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $_currentConfig = array();
|
||||
private $_currentConfig = [];
|
||||
|
||||
/**
|
||||
* 实例化一个当前配置
|
||||
@ -33,7 +33,7 @@ class Typecho_Config implements Iterator
|
||||
* @access public
|
||||
* @param mixed $config 配置列表
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
public function __construct($config = [])
|
||||
{
|
||||
/** 初始化参数 */
|
||||
$this->setDefault($config);
|
||||
@ -43,10 +43,12 @@ class Typecho_Config implements Iterator
|
||||
* 工厂模式实例化一个当前配置
|
||||
*
|
||||
* @access public
|
||||
* @param array $config 配置列表
|
||||
*
|
||||
* @param array|string $config 配置列表
|
||||
*
|
||||
* @return Typecho_Config
|
||||
*/
|
||||
public static function factory($config = array())
|
||||
public static function factory($config = []): Typecho_Config
|
||||
{
|
||||
return new Typecho_Config($config);
|
||||
}
|
||||
@ -55,11 +57,13 @@ class Typecho_Config implements Iterator
|
||||
* 设置默认的配置
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param mixed $config 配置信息
|
||||
* @param boolean $replace 是否替换已经存在的信息
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDefault($config, $replace = false)
|
||||
public function setDefault($config, bool $replace = false)
|
||||
{
|
||||
if (empty($config)) {
|
||||
return;
|
||||
@ -130,7 +134,7 @@ class Typecho_Config implements Iterator
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function valid()
|
||||
public function valid(): bool
|
||||
{
|
||||
return false !== $this->current();
|
||||
}
|
||||
@ -142,9 +146,9 @@ class Typecho_Config implements Iterator
|
||||
* @param string $name 配置名称
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
public function __get(string $name)
|
||||
{
|
||||
return isset($this->_currentConfig[$name]) ? $this->_currentConfig[$name] : NULL;
|
||||
return $this->_currentConfig[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,7 +159,7 @@ class Typecho_Config implements Iterator
|
||||
* @param mixed $value 配置值
|
||||
* @return void
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
public function __set(string $name, $value)
|
||||
{
|
||||
$this->_currentConfig[$name] = $value;
|
||||
}
|
||||
@ -165,10 +169,10 @@ class Typecho_Config implements Iterator
|
||||
*
|
||||
* @access public
|
||||
* @param string $name 配置名称
|
||||
* @param array $args 参数
|
||||
* @param array|null $args 参数
|
||||
* @return void
|
||||
*/
|
||||
public function __call($name, $args)
|
||||
public function __call(string $name, ?array $args)
|
||||
{
|
||||
echo $this->_currentConfig[$name];
|
||||
}
|
||||
@ -180,7 +184,7 @@ class Typecho_Config implements Iterator
|
||||
* @param string $name 配置名称
|
||||
* @return boolean
|
||||
*/
|
||||
public function __isSet($name)
|
||||
public function __isSet(string $name): bool
|
||||
{
|
||||
return isset($this->_currentConfig[$name]);
|
||||
}
|
||||
@ -191,8 +195,16 @@ class Typecho_Config implements Iterator
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return serialize($this->_currentConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->_currentConfig;
|
||||
}
|
||||
}
|
||||
|
@ -61,8 +61,7 @@ class Typecho_Db
|
||||
/**
|
||||
* 默认配置
|
||||
*
|
||||
* @access private
|
||||
* @var Typecho_Config
|
||||
* @var array
|
||||
*/
|
||||
private $_config;
|
||||
|
||||
@ -109,9 +108,10 @@ class Typecho_Db
|
||||
*
|
||||
* @param mixed $adapterName 适配器名称
|
||||
* @param string $prefix 前缀
|
||||
*
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function __construct($adapterName, $prefix = 'typecho_')
|
||||
public function __construct($adapterName, string $prefix = 'typecho_')
|
||||
{
|
||||
/** 获取适配器名称 */
|
||||
$this->_adapterName = $adapterName;
|
||||
@ -119,16 +119,20 @@ class Typecho_Db
|
||||
/** 数据库适配器 */
|
||||
$adapterName = 'Typecho_Db_Adapter_' . $adapterName;
|
||||
|
||||
if (!call_user_func(array($adapterName, 'isAvailable'))) {
|
||||
if (!call_user_func([$adapterName, 'isAvailable'])) {
|
||||
throw new Typecho_Db_Exception("Adapter {$adapterName} is not available");
|
||||
}
|
||||
|
||||
$this->_prefix = $prefix;
|
||||
|
||||
/** 初始化内部变量 */
|
||||
$this->_pool = array();
|
||||
$this->_connectedPool = array();
|
||||
$this->_config = array();
|
||||
$this->_pool = [];
|
||||
$this->_connectedPool = [];
|
||||
|
||||
$this->_config = [
|
||||
self::READ => [],
|
||||
self::WRITE => []
|
||||
];
|
||||
|
||||
//实例化适配器对象
|
||||
$this->_adapter = new $adapterName();
|
||||
@ -140,7 +144,7 @@ class Typecho_Db
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getAdapterName()
|
||||
public function getAdapterName(): string
|
||||
{
|
||||
return $this->_adapterName;
|
||||
}
|
||||
@ -151,54 +155,69 @@ class Typecho_Db
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getPrefix()
|
||||
public function getPrefix(): string
|
||||
{
|
||||
return $this->_prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* getConfig
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
* @param Typecho_Config $config
|
||||
* @param int $op
|
||||
*/
|
||||
public function getConfig()
|
||||
public function addConfig(Typecho_Config $config, int $op)
|
||||
{
|
||||
return $this->_config;
|
||||
if ($op & self::READ) {
|
||||
$this->_config[self::READ][] = $config;
|
||||
}
|
||||
|
||||
if ($op & self::WRITE) {
|
||||
$this->_config[self::WRITE][] = $config;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getConfig
|
||||
*
|
||||
* @param int $op
|
||||
*
|
||||
* @return Typecho_Config
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function getConfig(int $op): Typecho_Config
|
||||
{
|
||||
if (empty($this->_config[$op])) {
|
||||
/** Typecho_Db_Exception */
|
||||
throw new Typecho_Db_Exception('Missing Database Connection');
|
||||
}
|
||||
|
||||
$key = array_rand($this->_config[$op]);
|
||||
return $this->_config[$op][$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置连接池
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function flushPool()
|
||||
{
|
||||
$this->_connectedPool = array();
|
||||
$this->_connectedPool = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择数据库
|
||||
*
|
||||
* @param int $op
|
||||
* @return Typecho_Db_Adapter
|
||||
*
|
||||
* @param int $op
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function selectDb($op)
|
||||
public function selectDb(int $op)
|
||||
{
|
||||
if (!isset($this->_connectedPool[$op])) {
|
||||
if (empty($this->_pool[$op])) {
|
||||
/** Typecho_Db_Exception */
|
||||
throw new Typecho_Db_Exception('Missing Database Connection');
|
||||
}
|
||||
|
||||
//获取相应读或写服务器连接池中的一个
|
||||
$selectConnection = rand(0, count($this->_pool[$op]) - 1);
|
||||
//获取随机获得的连接池配置
|
||||
$selectConnectionConfig = $this->_config[$this->_pool[$op][$selectConnection]];
|
||||
$selectConnectionConfig = $this->getConfig($op);
|
||||
$selectConnectionHandle = $this->_adapter->connect($selectConnectionConfig);
|
||||
$this->_connectedPool[$op] = &$selectConnectionHandle;
|
||||
|
||||
$this->_connectedPool[$op] = $selectConnectionHandle;
|
||||
}
|
||||
|
||||
return $this->_connectedPool[$op];
|
||||
@ -209,7 +228,7 @@ class Typecho_Db
|
||||
*
|
||||
* @return Typecho_Db_Query
|
||||
*/
|
||||
public function sql()
|
||||
public function sql(): Typecho_Db_Query
|
||||
{
|
||||
return new Typecho_Db_Query($this->_adapter, $this->_prefix);
|
||||
}
|
||||
@ -218,35 +237,25 @@ class Typecho_Db
|
||||
* 为多数据库提供支持
|
||||
*
|
||||
* @access public
|
||||
* @param Typecho_Db $db 数据库实例
|
||||
* @param array $config 数据库实例
|
||||
* @param integer $op 数据库操作
|
||||
* @return void
|
||||
*/
|
||||
public function addServer($config, $op)
|
||||
public function addServer(array $config, int $op)
|
||||
{
|
||||
$this->_config[] = Typecho_Config::factory($config);
|
||||
$key = count($this->_config) - 1;
|
||||
|
||||
/** 将连接放入池中 */
|
||||
switch ($op) {
|
||||
case self::READ:
|
||||
case self::WRITE:
|
||||
$this->_pool[$op][] = $key;
|
||||
break;
|
||||
default:
|
||||
$this->_pool[self::READ][] = $key;
|
||||
$this->_pool[self::WRITE][] = $key;
|
||||
break;
|
||||
}
|
||||
$this->addConfig(Typecho_Config::factory($config), $op);
|
||||
$this->flushPool();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本
|
||||
*
|
||||
* @param int $op
|
||||
*
|
||||
* @param int $op
|
||||
*
|
||||
* @return string
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function getVersion($op = self::READ)
|
||||
public function getVersion(int $op = self::READ): string
|
||||
{
|
||||
return $this->_adapter->getVersion($this->selectDb($op));
|
||||
}
|
||||
@ -270,7 +279,7 @@ class Typecho_Db
|
||||
* @return Typecho_Db
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public static function get()
|
||||
public static function get(): Typecho_Db
|
||||
{
|
||||
if (empty(self::$_instance)) {
|
||||
/** Typecho_Db_Exception */
|
||||
@ -283,24 +292,31 @@ class Typecho_Db
|
||||
/**
|
||||
* 选择查询字段
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $field 查询字段
|
||||
* @param ...$ags
|
||||
*
|
||||
* @return Typecho_Db_Query
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function select()
|
||||
public function select(...$ags): Typecho_Db_Query
|
||||
{
|
||||
$this->selectDb(self::READ);
|
||||
|
||||
$args = func_get_args();
|
||||
return call_user_func_array(array($this->sql(), 'select'), $args ? $args : array('*'));
|
||||
return call_user_func_array([$this->sql(), 'select'], $args ?: ['*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新记录操作(UPDATE)
|
||||
*
|
||||
* @param string $table 需要更新记录的表
|
||||
*
|
||||
* @return Typecho_Db_Query
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function update($table)
|
||||
public function update(string $table): Typecho_Db_Query
|
||||
{
|
||||
$this->selectDb(self::WRITE);
|
||||
|
||||
return $this->sql()->update($table);
|
||||
}
|
||||
|
||||
@ -308,10 +324,14 @@ class Typecho_Db
|
||||
* 删除记录操作(DELETE)
|
||||
*
|
||||
* @param string $table 需要删除记录的表
|
||||
*
|
||||
* @return Typecho_Db_Query
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function delete($table)
|
||||
public function delete(string $table): Typecho_Db_Query
|
||||
{
|
||||
$this->selectDb(self::WRITE);
|
||||
|
||||
return $this->sql()->delete($table);
|
||||
}
|
||||
|
||||
@ -319,10 +339,14 @@ class Typecho_Db
|
||||
* 插入记录操作(INSERT)
|
||||
*
|
||||
* @param string $table 需要插入记录的表
|
||||
*
|
||||
* @return Typecho_Db_Query
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function insert($table)
|
||||
public function insert(string $table): Typecho_Db_Query
|
||||
{
|
||||
$this->selectDb(self::WRITE);
|
||||
|
||||
return $this->sql()->insert($table);
|
||||
}
|
||||
|
||||
@ -342,19 +366,20 @@ class Typecho_Db
|
||||
* @param mixed $query 查询语句或者查询对象
|
||||
* @param int $op 数据库读写状态
|
||||
* @param string $action 操作动作
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function query($query, $op = self::READ, $action = self::SELECT)
|
||||
public function query($query, int $op = self::READ, string $action = self::SELECT)
|
||||
{
|
||||
$table = NULL;
|
||||
$table = null;
|
||||
|
||||
/** 在适配器中执行查询 */
|
||||
if ($query instanceof Typecho_Db_Query) {
|
||||
$action = $query->getAttribute('action');
|
||||
$table = $query->getAttribute('table');
|
||||
$op = (self::UPDATE == $action || self::DELETE == $action
|
||||
|| self::INSERT == $action) ? self::WRITE : self::READ;
|
||||
|| self::INSERT == $action) ? self::WRITE : self::READ;
|
||||
} else if (!is_string($query)) {
|
||||
/** 如果query不是对象也不是字符串,那么将其判断为查询资源句柄,直接返回 */
|
||||
return $query;
|
||||
@ -389,24 +414,26 @@ class Typecho_Db
|
||||
* 一次取出所有行
|
||||
*
|
||||
* @param mixed $query 查询对象
|
||||
* @param array $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
|
||||
* @param array|null $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
|
||||
*
|
||||
* @return array
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function fetchAll($query, array $filter = NULL)
|
||||
public function fetchAll($query, ?array $filter = null): array
|
||||
{
|
||||
//执行查询
|
||||
$resource = $this->query($query, self::READ);
|
||||
$result = array();
|
||||
$result = [];
|
||||
|
||||
/** 取出过滤器 */
|
||||
if (!empty($filter)) {
|
||||
list($object, $method) = $filter;
|
||||
[$object, $method] = $filter;
|
||||
}
|
||||
|
||||
//取出每一行
|
||||
while ($rows = $this->_adapter->fetch($resource)) {
|
||||
//判断是否有过滤器
|
||||
$result[] = $filter ? call_user_func(array(&$object, $method), $rows) : $rows;
|
||||
$result[] = $filter ? call_user_func([&$object, $method], $rows) : $rows;
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -416,41 +443,45 @@ class Typecho_Db
|
||||
* 一次取出一行
|
||||
*
|
||||
* @param mixed $query 查询对象
|
||||
* @param array $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
|
||||
* @param array|null $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function fetchRow($query, array $filter = NULL)
|
||||
public function fetchRow($query, ?array $filter = null)
|
||||
{
|
||||
$resource = $this->query($query, self::READ);
|
||||
|
||||
/** 取出过滤器 */
|
||||
if ($filter) {
|
||||
list($object, $method) = $filter;
|
||||
[$object, $method] = $filter;
|
||||
}
|
||||
|
||||
return ($rows = $this->_adapter->fetch($resource)) ?
|
||||
($filter ? $object->$method($rows) : $rows) :
|
||||
array();
|
||||
($filter ? $object->$method($rows) : $rows) :
|
||||
[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 一次取出一个对象
|
||||
*
|
||||
* @param mixed $query 查询对象
|
||||
* @param array $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
|
||||
* @param array|null $filter 行过滤器函数,将查询的每一行作为第一个参数传入指定的过滤器中
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Typecho_Db_Exception
|
||||
*/
|
||||
public function fetchObject($query, array $filter = NULL)
|
||||
public function fetchObject($query, ?array $filter = null)
|
||||
{
|
||||
$resource = $this->query($query, self::READ);
|
||||
|
||||
/** 取出过滤器 */
|
||||
if ($filter) {
|
||||
list($object, $method) = $filter;
|
||||
[$object, $method] = $filter;
|
||||
}
|
||||
|
||||
return ($rows = $this->_adapter->fetchObject($resource)) ?
|
||||
($filter ? $object->$method($rows) : $rows) :
|
||||
new stdClass();
|
||||
($filter ? $object->$method($rows) : $rows) :
|
||||
new stdClass();
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ interface Typecho_Db_Adapter
|
||||
* 数据库连接函数
|
||||
*
|
||||
* @param Typecho_Config $config 数据库配置
|
||||
* @return resource
|
||||
* @return mixed
|
||||
*/
|
||||
public function connect(Typecho_Config $config);
|
||||
|
||||
|
@ -39,7 +39,7 @@ class Typecho_Db_Adapter_Mysql implements Typecho_Db_Adapter
|
||||
*
|
||||
* @param Typecho_Config $config 数据库配置
|
||||
* @throws Typecho_Db_Exception
|
||||
* @return resource
|
||||
* @return mixed
|
||||
*/
|
||||
public function connect(Typecho_Config $config)
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ class Typecho_Db_Adapter_Mysqli implements Typecho_Db_Adapter
|
||||
* 数据库连接字符串标示
|
||||
*
|
||||
* @access private
|
||||
* @var resource
|
||||
* @var mysqli
|
||||
*/
|
||||
private $_dbLink;
|
||||
|
||||
@ -39,12 +39,18 @@ class Typecho_Db_Adapter_Mysqli implements Typecho_Db_Adapter
|
||||
*
|
||||
* @param Typecho_Config $config 数据库配置
|
||||
* @throws Typecho_Db_Exception
|
||||
* @return resource
|
||||
* @return mixed
|
||||
*/
|
||||
public function connect(Typecho_Config $config)
|
||||
{
|
||||
|
||||
if ($this->_dbLink = @new MySQLi($config->host, $config->user, $config->password, $config->database, (empty($config->port) ? '' : $config->port))) {
|
||||
if ($this->_dbLink = @mysqli_connect(
|
||||
$config->host,
|
||||
$config->user,
|
||||
$config->password,
|
||||
$config->database,
|
||||
(empty($config->port) ? null : $config->port))
|
||||
) {
|
||||
if ($config->charset) {
|
||||
$this->_dbLink->query("SET NAMES '{$config->charset}'");
|
||||
}
|
||||
|
@ -165,10 +165,10 @@ class Typecho_Validate
|
||||
* 是否为空
|
||||
*
|
||||
* @access public
|
||||
* @param string $str 待处理的字符串
|
||||
* @param string|null $str 待处理的字符串
|
||||
* @return boolean
|
||||
*/
|
||||
public function required(string $str): bool
|
||||
public function required(?string $str): bool
|
||||
{
|
||||
return !empty($this->_data[$this->_key]);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user