-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
500 lines (298 loc) · 332 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>骑在墙上の博客</title>
<link href="/atom.xml" rel="self"/>
<link href="https://hexo.lilis.xin/"/>
<updated>2021-07-15T06:56:59.318Z</updated>
<id>https://hexo.lilis.xin/</id>
<author>
<name>🐣</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Linux网络io模型</title>
<link href="https://hexo.lilis.xin/posts/3807630236/"/>
<id>https://hexo.lilis.xin/posts/3807630236/</id>
<published>2021-07-13T09:38:07.000Z</published>
<updated>2021-07-15T06:56:59.318Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>Linux下的五个基本io模型</p><a id="more"></a><h1>基本概念</h1><h2 id="内核空间和用户空间"><a class="header-anchor" href="#内核空间和用户空间">➡️</a>内核空间和用户空间</h2><h3 id="Linux的进程地址空间"><a class="header-anchor" href="#Linux的进程地址空间">➡️</a>Linux的进程地址空间</h3><p><code>进程地址空间</code>表示位用户进程看到的内存地址空间</p><h4 id="32位系统的进程地址空间"><a class="header-anchor" href="#32位系统的进程地址空间">➡️</a>32位系统的进程地址空间</h4><p>32位系统下虚拟地址空间范围位为<code>0~2³²(4GB)</code>,其中<code>0~3GB</code>为用户空间<code>user space</code>,<code>3~4GB</code>为内核空间<code>kernel space</code>。<br>因为<code>内核</code>的虚拟地址空间只有1GB,但是需要访问整个4GB的物理空间,因此从物理地址<code>0~896MB</code>的部分,直接加上<code>3GB</code>的偏移,就得到了对应的虚拟地址,这种映射方式被称为<code>线性/直接映射Direct Map</code>。</p><p>而<code>896M~4GB</code>的物理地址部分<code>ZONE_HIGHMEM</code>需要映射到<code>3G+896M</code>~<code>4GB</code>这<code>128MB</code>的虚拟地址空间。<br>采用的是做法是,<code>ZONE_HIGHMEM</code>中的一段段物理内存和这<code>128M</code>中的一段虚拟空间建立映射完成后断开与这部分虚拟空间的映射关系,然后<code>ZONE_HIGHMEM</code>中其他的物理内存可以继续往这个区域映射,即<code>动态映射</code>。</p><p>用户空间虽然只能访问虚拟地址<code>0~3G</code>的空间,但是处于性能的考虑Linux中内核使用的地址也是映射到进程地址空间的,虽然不能访问内核所属的<code>3G~4G</code>,但还是可以看到这一段的地址空间,因此进程的虚拟地址空间可视为整个4GB。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/内存空间映射关系.png " class="full-image" title="内存空间映射关系"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><h4 id="64位系统的进程地址空间"><a class="header-anchor" href="#64位系统的进程地址空间">➡️</a>64位系统的进程地址空间</h4><h5 id="地址空间大小不是232,也不是264,而一般是248。"><a class="header-anchor" href="#地址空间大小不是232,也不是264,而一般是248。">➡️</a>地址空间大小不是2<sup>32</sup>,也不是2<sup>64</sup>,而一般是2<sup>48</sup>。</h5><p>因为并不需要 2<sup>64</sup> 这么大的寻址空间,过大空间只会导致资源的浪费。64位Linux一般使用48位来表示虚拟地址空间,40位表示物理地址(我这台机器是46位物理地址),这可通过一下命令来查看。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">root in ~ λ cat /proc/cpuinfo</span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/内存地址长度.png " class="full-image" title="cat /proc/cpuinfo"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><h5 id="用户空间和内核空间。"><a class="header-anchor" href="#用户空间和内核空间。">➡️</a>用户空间和内核空间。</h5><ul><li><code>0x0000000000000000~0x00007fffffffffff</code>表示用户空间</li><li><code>0xFFFF800000000000~0xFFFFFFFFFFFFFFFF</code>表示内核空间</li></ul><p>共提供 <code>256TB(2^48)</code> 的寻址空间。这两个区间的特点是,第 <code>47位</code>与 <code>48~63位</code>相同,若这些位为 0 表示用户空间,否则表示内核空间。</p><h5 id="内存映射"><a class="header-anchor" href="#内存映射">➡️</a>内存映射</h5><p>在64位系统中,内核空间的映射变的简单了,因为内存空间已经足够大了,所以需要映射什么可以直接映射<br>用户空间的映射和32位没有什么区别</p><h2 id="进程切换"><a class="header-anchor" href="#进程切换">➡️</a>进程切换</h2><p>无论是在多核还是单核系统中,一个CPU看上去都像是在并发的执行多个进程,这是通过处理器在进程间切换来实现的。</p><p>操作系统实现这种交错执行的机制称为<code>上下文切换</code>。</p><p>在这种机制下,从进程的视角来看就像是所有进程同时执行的效果。</p><p>在任一时刻,单一处理器核心只能处理一个进程(超线程除外,超线程可以把每一个物理核心当成两个用)。</p><p>当操作系统决定要把控制权从当前进程转移到某个新进程时,就会进行上下文切换,即保存当前进程的上下文,恢复新进程的上下文,然后将控制权传递到新进程,新进程就会从上次停止的地方开始。</p><h3 id="进程"><a class="header-anchor" href="#进程">➡️</a>进程</h3><ul><li>一个独立的逻辑控制流,它提供一个假象,好像我们的程序独占的使用处理器</li><li>一个私有的地址空间,它提供一个假象,好像我们的程序独占地使用存储器系统</li></ul><p>而实际上,进程是轮流使用处理器的。<br>每个进程执行他的流的一部分,然后被暂时挂起,然后轮到其他进程。<br>对于一个运行在这些进程之一的上下文中的程序,他看上去就像是在独占的使用处理器</p><h3 id="进程切换流程"><a class="header-anchor" href="#进程切换流程">➡️</a>进程切换流程</h3><ul><li>保存上下文。</li><li>更新PCB信息。</li><li>把进程的PCB移入相应的队列。</li><li>选择另一个进程执行,并更新其PCB。</li><li>更新内存管理的数据结构。</li><li>恢复上下文。</li></ul><h3 id="用户模式和内核模式"><a class="header-anchor" href="#用户模式和内核模式">➡️</a>用户模式和内核模式</h3><p>为了使操作系用内核提供一个无懈可击的进程抽象,处理器必须提供一种机制,限制一个应用可以执行的指令以及它可以访问的地址空间范围。</p><p>处理器通常是用某个控制寄存器中的一个模式位来提供这种功能的,该寄存器描述了进程当前享有的特权。</p><p>当设置了模式位时,进程就运行在内核模式中,即超级用户模式。</p><p>一个运行在内核模式的进程可以执行指令集中的任何指令,并且可以访问系统中任何存储器位置。</p><p>没有设置模式位时,进程就运行在用户模式中。用户模式中的进程不允许执行特权指令,比如停止处理器,改变模式位,或者发起一个I/O操作。也不允许用户模式中的进程直接引用地址空间中内核区内的代码和数据。</p><p>运行应用程序代码的进程初始时是在用户模式中的。</p><p><font color="#f00">进程切换只发生在内核态!</font></p><h2 id="进程阻塞"><a class="header-anchor" href="#进程阻塞">➡️</a>进程阻塞</h2><p>正在执行的进程,由于期待的某些事件未发生,如请求系统资源失败、等待某种操作的完成、新数据尚未到达或无新工作做等,则由系统自动执行阻塞原语(Block),使自己由运行状态变为阻塞状态。可见,进程的阻塞是进程自身的一种主动行为,也因此只有处于运行态的进程(获得CPU),才可能将其转为阻塞状态。</p><p>阻塞原语的执行过程是:</p><ol><li>找到将要被阻塞进程的标识号对应的PCB。</li><li>若该进程为运行状态,则保护其现场,将其状态转为阻塞状态,停止运行。</li><li>把该PCB插入到相应事件的等待队列中去。</li></ol><p>当被阻塞进程所期待的事件出现时,如它所启动的I/O操作已完成或其所期待的数据已到达,则由有关进程(比如,提供数据的进程)调用唤醒原语(Wakeup),将等待该事件的进程唤醒。</p><p>唤醒原语的执行过程是:</p><ol><li>在该事件的等待队列中找到相应进程的PCB。</li><li>将其从等待队列中移出,并置其状态为就绪状态。</li><li>把该PCB插入就绪队列中,等待调度程序调度。</li></ol><p>需要注意的是,Block原语和Wakeup原语是一对作用刚好相反的原语,必须成对使用。 Block原语是由被阻塞进程自我调用实现的,而Wakeup原语则是由一个与被唤醒进程相合作或被其他相关的进程调用实现的。</p><h3 id="进程的基本状态"><a class="header-anchor" href="#进程的基本状态">➡️</a>进程的基本状态</h3><ul><li>就绪状态 :一个进程获得了除处理机外的一切所需资源,一旦得到处理机即可运行,则称此进程处于就绪状态。</li><li>执行状态:当一个进程在处理机上运行时,则称该进程处于运行状态。</li><li>阻塞状态:一个进程正在等待某一事件发生(例如请求I/O而等待I/O完成等)而暂时停止运行,这时即使把处理机分配给进程也无法运行,故称该进程处于阻塞状态。</li><li>挂起状态:由于IO的速度慢于CPU的运算速度,经常出现CPU等待I/O的情况。这时OS需要将主存中的进程对换至外存。在进程行为模式中需要增加一个新的挂起(suspend)状态。当内存中所有进程阻塞时,OS可将一进程置为挂起态并交换到外存,再调入另一个进程执行。</li><li>新建状态:进程刚创建,但还不能运行,OS还没有把它加到可执行进程组中,通常是还没有加载到主存中的新进程。</li><li>退出状态:OS从可执行进程组中释放出的进程,或者是因为它自身停止了,或者是因为某种原因被取消。进程不在适合执行,但与作业相关的表和其它信息临时被OS保留起来,为其他程序提供所需信息。</li><li>活跃就绪:指进程在主存并旦可被调度的状态。</li><li>静止就绪:指进程被对换到辅存时的就绪状态,是不能被直接调度的状态,只有当主存中没有活跃就绪态进程,或者是挂起态进程具有更高的优先级,系统将把挂起就绪态进程调回主存并转换为活跃就绪。</li><li>活跃阻塞:指进程在主存中。一旦等待的事件产生,便进入活跃就绪状态。</li><li>静止阻塞:指进程对换到辅存时的阻塞状态。一旦等待的事件产生,便进入静止就绪状态。</li></ul><h2 id="文件描述符fd"><a class="header-anchor" href="#文件描述符fd">➡️</a>文件描述符fd</h2><h3 id="概念"><a class="header-anchor" href="#概念">➡️</a>概念</h3><p>文件描述符(File descriptor)是计算机科学中的一个术语,是一个用于表述指向文件的引用的抽象化概念。</p><p>Linux 系统中,把一切都看做是文件,当进程打开现有文件或创建新文件时,内核向进程返回一个文件描述符,文件描述符就是内核为了高效管理已被打开的文件所创建的索引,用来指向被打开的文件,所有执行I/O操作的系统调用都会通过文件描述符。</p><h3 id="文件描述符、文件、进程间的关系"><a class="header-anchor" href="#文件描述符、文件、进程间的关系">➡️</a>文件描述符、文件、进程间的关系</h3><ul><li>每个文件描述符会与一个打开的文件相对应</li><li>不同的文件描述符也可能指向同一个文件</li><li>相同的文件可以被不同的进程打开,也可以在同一个进程被多次打开</li></ul><h3 id="系统为维护文件描述符,建立了三个表"><a class="header-anchor" href="#系统为维护文件描述符,建立了三个表">➡️</a>系统为维护文件描述符,建立了三个表</h3><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/113418861-593aafc8a9744_fix732.png " class="full-image" title="系统为了维护文件描述符所建立的三个表"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><h3 id="文件描述符限制"><a class="header-anchor" href="#文件描述符限制">➡️</a>文件描述符限制</h3><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/2289371477-593aaff35bc21_fix732.png " class="full-image" title="文件描述符限制"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p>永久修改用户级限制时有三种设置类型:</p><ul><li><p>soft 指的是当前系统生效的设置值</p></li><li><p>hard 指的是系统中所能设定的最大值</p></li><li><p>指的是同时设置了 soft 和 hard 的值</p><ul><li><a href="https://wangchujiang.com/linux-command/c/ulimit.html" title="ulimit" target>Linux命令 ulimit</a></li><li><a href="https://wangchujiang.com/linux-command/c/sysctl.html" title="sysctl" target>Linux命令 sysctl</a></li></ul></li></ul><h3 id="查看某个进程的文件描述符"><a class="header-anchor" href="#查看某个进程的文件描述符">➡️</a>查看某个进程的文件描述符</h3><ul><li>找到进程ID</li><li><code>ls -lh /proc/{刚刚找到的进程ID}/fd</code></li></ul><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/docker服务下的一个进程的文件描述符.png " class="full-image" title="docker服务下的一个进程的文件描述符"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><h2 id="缓存-IO"><a class="header-anchor" href="#缓存-IO">➡️</a>缓存 IO</h2><p>缓存I/O又被称作标准I/O,大多数文件系统的默认I/O操作都是缓存I/O。在Linux的缓存I/O机制中,数据先从磁盘复制到内核空间的缓冲区,然后从内核空间缓冲区复制到应用程序的地址空间。</p><p>读操作:操作系统检查内核的缓冲区有没有需要的数据,如果已经缓存了,那么就直接从缓存中返回;否则从磁盘中读取,然后缓存在操作系统的缓存中。</p><p>写操作:将数据从用户空间复制到内核空间的缓存中。这时对用户程序来说写操作就已经完成,至于什么时候再写到磁盘中由操作系统决定,除非显示地调用了sync同步命令。</p><p>延迟写减少了磁盘读写次数,但是却降低了文件内容的更新速度,使得欲写到文件中的数据在一段时间内并没有写到磁盘上。当系统发生故障时,这种延迟可能造成文件更新内容的丢失。为了保证磁盘上实际文件系统与缓冲区高速缓存中内容的一致性,UNIX系统提供了<code>sync</code>、<code>fsync</code>和<code>fdatasync</code>三个函数。</p><ol><li><code>sync</code>函数只是将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。通常称为update的系统守护进程会周期性地(一般每隔30秒)调用<code>sync</code>函数。这就保证了定期冲洗内核的块缓冲区。命令<code>sync(1)</code>也调用<code>sync</code>函数。</li><li><code>fsync</code>函数只对由文件描述符<code>filedes</code>指定的单一文件起作用,并且等待写磁盘操作结束,然后返回。<code>fsync</code>可用于数据库这样的应用程序,这种应用程序需要确保将修改过的块立即写到磁盘上。</li><li><code>fdatasync</code>函数类似于<code>fsync</code>,但它只影响文件的数据部分。而除数据外,<code>fsync</code>还会同步更新文件的属性。</li></ol><p><code>fsync</code>不但更新数据,还会更新元数据-文件的属性,但<code>fdatasync</code>仅更新数据。</p><p>对于提供事务支持的数据库,在事务提交时,都要确保事务日志(包含该事务所有的修改操作以及一个提交记录)完全写到硬盘上,才认定事务提交成功并返回给应用层。</p><pre><code>缺点:不能直接在应用程序地址空间和磁盘之间进行数据传输。</code></pre><hr><h1>Linux 网络IO模型</h1><p>I/O是计算机的输入输出,通俗一点讲是计算机数据的流动,包括CPU、内存、磁盘、网络、外设的数据流程,是针对不同主体而言的数据的输入和输出。</p><p>磁盘控制器是典型的设备控制器,与计算机总线相连,主要负责把数据写入磁盘和从磁盘读出数据,CPU通过总线将数据传送给磁盘控制器,再由磁盘进行处理,从而产生磁盘I/O。</p><p>网络适配器,即网卡,是计算机之间通过网络传送数据的控制器,位于OSI模型的物理层和数据链路层,简单来说,网卡是将计算机的数据封装为帧,并通过网线(对无线网络来说就是电磁波)将数据发送到网络上去;还负责接收网络上其它设备传过来的帧,并将帧重新组合成数据,发送到所在的电脑中。<br>具体来说就是在网络协议支持下,一个网络主机的进程通过网络与网络中其他主机的进程进行数据传输的过程,这一数据的传输过程就是网络I/O。</p><h2 id="socket"><a class="header-anchor" href="#socket">➡️</a>socket</h2><p>在操作系统中,所有的I/O设备(磁盘、外设、网络等)都被模型化为文件,所有的输入和输出动作都被当成相应的文件的读和写来执行,这些文件通过操作系统的VFS机制(虚拟文件系统),以文件系统形式挂载在Linux内核中,对外提供一致的文件操作接口。</p><p>在网络通信中,为了适配各种网络协议的复杂性,而使操作系统能够统一操作网络中的数据,在网络与进程间增加了一个抽象层,即套接字<code>socket</code>。<br>客户端和服务器通过使用<code>socket</code>接口建立连接,连接以文件描述符形式提供给进程,套接字接口提供了打开和关闭套接字描述符的函数,客户端和服务器通过读写这些描述符来实现彼此间的通信。所以,<code>socket</code>是一种特殊的文件。</p><h2 id="I-O模型"><a class="header-anchor" href="#I-O模型">➡️</a>I/O模型</h2><p><code>I/O</code>操作的过程可以大概总结如下:</p><p>输入:</p><ul><li>进程向内核发起一个系统调用(<code>read</code>、<code>readv</code>、<code>recv</code>、<code>recvfrom</code>、<code>recvmsg</code>);</li><li>内核收到系统调用,通知<code>I/O</code>设备读取数据;</li><li>设备将数据载入内核缓冲区;</li><li>内核缓冲区接到数据后,复制到用户进程的缓冲区;</li><li>进程缓冲区得到数据,通知内核;</li><li>内核将控制权交给应用进程,进程继续下一步操作;<br><br><br>输出:</li><li>进程向内核发起一个系统调用(<code>write</code>、<code>writev</code>、<code>send</code>、<code>sendto</code>、<code>sendmsg</code>);</li><li>内核收到系统调用,内核将数据从应用进程的缓冲区到内核缓冲区(或设备缓冲区,如<code>Socket缓冲区</code>);</li><li>内核将控制权交给应用进程,由设备执行下一步操作(如磁盘将数据写到磁盘;网卡将数据通过网络发出);</li></ul><p>操作系统对于这些<code>I/O</code>操作有几种特定的处理方式,也就是<code>I/O模型</code>,包括<code>阻塞式I/O</code>、<code>非阻塞式I/O</code>、<code>I/O复用</code>、<code>信号驱动式I/O</code>、<code>异步I/O</code>。</p><h2 id="同步阻塞-IO(blocking-IO)"><a class="header-anchor" href="#同步阻塞-IO(blocking-IO)">➡️</a>同步阻塞 IO(blocking IO)</h2><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/阻塞式io模型.jpg" class="full-image" title="阻塞式io模型"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p>不管有无数据报到来,进程(线程)是阻塞于 <code>recvfrom</code> 系统调用的。<br>假如我们需要调用<code>read</code>方法来读取套接字,这个<code>read</code>方法就会触发操作系统内核的一次 recvfrom 系统调用。此时有以下两种情况:</p><ol><li>内核还未接收到远端数据。此时会阻塞在<code>等待数据</code>阶段</li><li>内核已经接收到远端数据。内核需要复制数据到用户空间,在复制过程中会阻塞在<code>将数据复制到用户空间</code>阶段。</li></ol><h2 id="同步非阻塞-IO(nonblocking-IO)"><a class="header-anchor" href="#同步非阻塞-IO(nonblocking-IO)">➡️</a>同步非阻塞 IO(nonblocking IO)</h2><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/同步非阻塞io模型.png" class="full-image" title="同步非阻塞io模型"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p>根据内核中的数据报有无准备好,有以下两种情形:</p><ol><li><p>当内核中的数据报还没准备好,此时 <code>recvfrom</code> 系统调用立即返回一个 <code>EWOULDBLOCK</code> 错误,即不会将用户进程(线程)置于阻塞状态。</p></li><li><p>当内核中的数据报已经准备好时,此时 <code>recvfrom</code> 系统调用,用户进程(线程)还是会阻塞,直到内核中的数据报已经拷贝到了用户空间,此时用户进程(线程)才会被唤醒来处理接收的数据报。</p></li></ol><h2 id="IO-多路复用(-IO-multiplexing)"><a class="header-anchor" href="#IO-多路复用(-IO-multiplexing)">➡️</a>IO 多路复用( IO multiplexing)</h2><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/io多路复用模型.png" class="full-image" title="io多路复用模型"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p>所谓 <code>I/O 多路复</code>用指的就是 <code>select</code>/<code>poll</code>/<code>epoll</code> 这一系列的多路选择器:支持单一线程同时监听多个文件描述符(<code>I/O 事件</code>),阻塞等待,并在其中某个文件描述符可读写时收到通知。 <code>I/O 复用</code>其实复用的不是 <code>I/O 连接</code>,而是复用线程,让一个 <code>thread of control</code> 能够处理多个连接(<code>I/O 事件</code>)。</p><p>整体流程上来说和<code>同步阻塞 IO</code>差不多,只是多路复用在<code>select</code>的时候可以监听多个<code>文件描述符</code>,以此来实现一个线程监听多个io事件,节省cpu的<code>线程切换</code>或<code>进程切换</code>消耗。</p><h2 id="信号驱动式IO(signal-driven-IO)"><a class="header-anchor" href="#信号驱动式IO(signal-driven-IO)">➡️</a>信号驱动式IO(signal-driven IO)</h2><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/信号驱动io模型.png" class="full-image" title="信号驱动io模型"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p>信号驱动 IO 模型在等待数据报期间是不会阻塞的,即用户进程(线程)发送一个 <code>sigaction</code> 系统调用后,此时立刻返回,并不会阻塞,然后用户进程(线程)继续执行(这一期间是不阻塞的);当数据报准备好时,此时内核就为该进程(线程)产生一个 <code>SIGIO</code> 信号,此时该进程(线程)就发生一次 <code>recvfrom</code> 系统调用将数据报从内核复制到用户空间,注意,这个阶段是阻塞的。</p><h2 id="异步非阻塞-IO(asynchronous-IO)"><a class="header-anchor" href="#异步非阻塞-IO(asynchronous-IO)">➡️</a>异步非阻塞 IO(asynchronous IO)</h2><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/异步io模型.png" class="full-image" title="异步io模型"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p>等待数据报到来和拷贝数据报到用户空间是完全交给内核来操作的,这一段时间用户是可以进行自己的操作的,等到数据报拷贝完成再通知用户进行数据处理操作。</p><p>和信号驱动io的区别是信号驱动模式在数据报到达后内核就会通知用户,然后由用户来主动发起调用来拷贝到用户空间,而异步模式则完全交给内核处理,用户在接到信号后就可以直接处理数据。</p><h2 id="5种io模型的比较"><a class="header-anchor" href="#5种io模型的比较">➡️</a>5种io模型的比较</h2><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/五种io模型的区别.png" class="full-image" title="五种io模型的区别"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><h1>golang io模型</h1><p>在go语言里,通过对<code>I/O 多路复用</code>的封装,且借助于 <code>Go runtime scheduler</code>对协程的高效调度,这个原生网络模型不论从适用性还是性能上都足以满足绝大部分的应用场景。</p><p><code>Go netpoll</code> 在不同的操作系统,其底层使用的 <code>I/O 多路复用</code>技术也不一样,可以从 Go 源码目录结构和对应代码文件了解 Go 在不同平台下的网络 I/O 模式的实现。比如,在 <code>Linux</code> 系统下基于 <code>epoll</code>,<code>freeBSD</code> 系统下基于 <code>kqueue</code>,以及 <code>Windows</code> 系统下基于 <code>iocp</code>。</p><br><p>一个典型的go tcp server。</p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"> <span class="string">"fmt"</span></span><br><span class="line"> <span class="string">"net"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> listen, err := net.Listen(<span class="string">"tcp"</span>, <span class="string">"0.0.0.0:8888"</span>)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> fmt.Println(<span class="string">"listen error: "</span>, err)</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> {</span><br><span class="line"> conn, listenErr := listen.Accept()</span><br><span class="line"> <span class="keyword">if</span> listenErr != <span class="literal">nil</span> {</span><br><span class="line"> fmt.Println(<span class="string">"accept error: "</span>, err)</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// start a new goroutine to handle the new connection</span></span><br><span class="line"> <span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">(conn net.Conn)</span></span> {</span><br><span class="line"> <span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> {</span><br><span class="line"> _ = conn.Close()</span><br><span class="line"> }()</span><br><span class="line"> </span><br><span class="line"> packet := <span class="built_in">make</span>([]<span class="keyword">byte</span>, <span class="number">1024</span>)</span><br><span class="line"> <span class="keyword">for</span> {</span><br><span class="line"> <span class="comment">// 如果没有可读数据,也就是读 buffer 为空,则阻塞</span></span><br><span class="line"> _, _ = conn.Read(packet)</span><br><span class="line"> <span class="comment">// 同理,不可写则阻塞</span></span><br><span class="line"> _, _ = conn.Write(packet)</span><br><span class="line"> }</span><br><span class="line"> }(conn)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这是一个基于<code>netpoll</code>来编写的<code>TCP Server</code>,对于开发者来说无需关心协程的调度和上下文切换。</p><blockquote><p>Go netpoll 通过在底层对 epoll/kqueue/iocp 的封装,从而实现了使用同步编程模式达到异步执行的效果。总结来说,所有的网络操作都以网络描述符 netFD 为中心实现。netFD 与底层 PollDesc 结构绑定,当在一个 netFD 上读写遇到 EAGAIN 错误时,就将当前 goroutine 存储到这个 netFD 对应的 PollDesc 中,同时调用 gopark 把当前 goroutine 给 park 住,直到这个 netFD 上再次发生读写事件,才将此 goroutine 给 ready 激活重新运行。显然,在底层通知 goroutine 再次发生读写等事件的方式就是 epoll/kqueue/iocp 等事件驱动机制。</p></blockquote><h1>参考链接</h1><ul><li><a href="https://blog.csdn.net/YuZhiHui_No1/article/details/46982231" title="linux内核内存的详细分配" target>linux内核内存的详细分配</a></li><li><a href="https://www.jishuchi.com/read/linux-interview/2830" title="Linux内存分配原理" target>Linux内存分配原理</a></li><li><a href="https://zhuanlan.zhihu.com/p/66794639" title="Linux的进程地址空间[一]" target>Linux的进程地址空间</a></li><li><a href="https://blog.csdn.net/lixungogogo/article/details/52202714" title="Linux下的进程1——进程概念,进程切换,上下文切换,虚拟地址空间" target>Linux下的进程1</a></li><li><a href="https://r00tk1ts.github.io/2017/08/26/Linux%E8%BF%9B%E7%A8%8B%E5%88%87%E6%8D%A2/" title="Linux内核学习——Linux进程切换" target>Linux内核学习——Linux进程切换</a></li><li><a href="http://c.biancheng.net/cpp/html/2590.html" title="进程控制:进程的创建、终止、阻塞、唤醒和切换" target>进程控制:进程的创建、终止、阻塞、唤醒和切换</a></li><li><a href="https://blog.csdn.net/Caoyang_He/article/details/80791581" title="进程的基本状态及转换和阻塞及挂起的理解" target>进程的基本状态及转换和阻塞及挂起的理解</a></li><li><a href="https://zh.wikipedia.org/wiki/%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6" title="文件描述符" target>维基百科 文件描述符</a></li><li><a href="https://segmentfault.com/a/1190000009724931" title="文件描述符(File Descriptor)简介" target>文件描述符(File Descriptor)简介</a></li><li><a href="https://blog.csdn.net/younger_china/article/details/51127127" title="linux 同步IO: sync、fsync与fdatasync" target>linux 同步IO: sync、fsync与fdatasync</a></li><li><a href="https://www.jianshu.com/p/2aa6357fe262" title="缓存IO与直接IO" target>缓存IO与直接IO</a></li><li><a href="https://cloud.tencent.com/developer/article/1446813" title="网络I/O原理、I/O模型及Linux监控命令" target>网络I/O原理、I/O模型及Linux监控命令</a></li><li><a href="https://www.jianshu.com/p/486b0965c296" title="聊聊Linux 五种IO模型" target>聊聊Linux 五种IO模型</a></li><li><a href="https://xie.infoq.cn/article/cba8e0883d75609a6c1866666" title="大白话详解 5 种网络 IO 模型" target>大白话详解5种网络IO模型</a></li><li><a href="https://www.infoq.cn/article/boeavgkiqmvcj8qjnbxk" title="Go netpoll I/O 多路复用构建原生网络模型之源码深度解析" target>Go netpoll I/O 多路复用构建原生网络模型之源码深度解析</a></li><li><a href="https://mcll.top/2019/04/07/go%E7%BD%91%E7%BB%9Cio%E6%A8%A1%E5%9E%8B%E5%88%86%E6%9E%90/" title="go网络io模型分析" target>go网络io模型分析</a></li></ul>]]></content>
<summary type="html">
<p>Linux下的五个基本io模型</p>
</summary>
<category term="Linux" scheme="https://hexo.lilis.xin/tags/Linux/"/>
<category term="网络io模型" scheme="https://hexo.lilis.xin/tags/%E7%BD%91%E7%BB%9Cio%E6%A8%A1%E5%9E%8B/"/>
</entry>
<entry>
<title>HTML-页面嵌入测试</title>
<link href="https://hexo.lilis.xin/posts/2649187286/"/>
<id>https://hexo.lilis.xin/posts/2649187286/</id>
<published>2021-02-06T00:33:52.000Z</published>
<updated>2021-02-08T09:19:03.305Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><h2 id="这是一个测试页面,测试iframe标签效果"><a class="header-anchor" href="#这是一个测试页面,测试iframe标签效果">➡️</a>这是一个测试页面,测试iframe标签效果</h2><a id="more"></a><div class="iframeContentBody" data-iframe-src="./embed_page/" data-iframe-ismobile="true" data-iframe-title="合成大西瓜(魔改版)"></div><div class="iframeContentBody" data-iframe-src="https://www.bing.com/" data-iframe-ismobile="false" data-iframe-title="必应"></div>]]></content>
<summary type="html">
<h2 id="这是一个测试页面,测试iframe标签效果"><a class="header-anchor" href="#这是一个测试页面,测试iframe标签效果">➡️</a>这是一个测试页面,测试iframe标签效果</h2>
</summary>
</entry>
<entry>
<title>CentOS 7安装TCP BBR拥塞算法</title>
<link href="https://hexo.lilis.xin/posts/907e528c/"/>
<id>https://hexo.lilis.xin/posts/907e528c/</id>
<published>2019-09-21T23:27:38.000Z</published>
<updated>2019-09-24T06:27:49.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><h4 id="认识BBR拥塞算法"><a class="header-anchor" href="#认识BBR拥塞算法">➡️</a>认识BBR拥塞算法</h4><p>从 4.9 开始,Linux 内核已经用上了该算法。根据以往的传统,Google 总是先在自家的生产环境上线运用后,才会将代码开源,此次也不例外。<br>根据实地测试,在部署了最新版内核并开启了 TCP BBR 的机器上,网速甚至可以提升好几个数量级。</p><a id="more"></a><p><code>TCP BBR拥塞算法</code>致力于解决两个问题:</p><ol><li>在有一定丢包率的网络链路上充分利用带宽。</li><li>降低网络链路上的 buffer 占用率,从而降低延迟。</li></ol><p>在标准<code>TCP</code>通讯的情况下,为了充分利用带宽所采用的方案是:不断增加发送窗口,直到开始丢包,然后较快地减小发送窗口。<br>这种做法在一般情况下没什么问题,但是在存在传输错误导致的丢包地情况下就没那么好使了。<br>在有一定的丢包率的延迟高、宽带大的链路上标准的<code>TCP拥塞控制</code>就会把发送窗口收敛到很小。<br>同时在网络中也有很多缓存空间用来吸收网络中的流量波动。由于标准的<code>TCP拥塞控制</code>是通过灌满带宽的方式来估算需要的发送窗口的,在连接的开始阶段,网络中的缓存空间就倾向于被占满。后续缓存空间会被逐渐释放,但并不会消失。客户端估计的水管容积总是略大于网络中除去缓存空间的实际容量。这个问题又被称之为<code>缓存区膨胀</code>。<br><code>缓存区膨胀</code>主要带来了两个问题:</p><ol><li>增加网络延迟。</li><li>在连接数较多时容易导致缓存区被填满导致丢包。</li></ol><p><code>TCP BBR</code>是用以下方法解决这两个问题的:</p><ol><li>既然分不清拥塞丢包和错误丢包那就不考虑丢包问题。</li><li>既然管满水管会导致缓存区膨胀那就估计带宽和延迟,不直接估计水管体积。</li></ol><p>带宽和延迟本身是没法同时测量的,测量最大带宽就需要把缓存区填满,测量最低延迟就需要把缓存区清空。<code>TCP BBR</code>所采用的方案是交替测量,用一段时间内的最大带宽和另一段时间内的最低延迟作为估计值。<br>在连接刚开始建立时,它采用了和标准<code>TCP</code>类似的慢启动,指数增长发送速率。而标准的<code>TCP拥塞控制</code>会在遇到任何一个丢包就立刻开始减速,开始拥塞避免。这时,标准<code>TCP拥塞控制</code>本意是达到带宽的最大值开始进行网络控制,但是在有一定的丢包率的情况下也有可能是单纯的网络丢包,这时网络并没有达到带宽的最大值;如果网络中存在缓存区,它也会一直到把缓存区填满才会放弃。<br><code>TCP BBR</code>则是根据收到的确认包,发现有效带宽不再增长时开始拥塞避免。这时,只要链路的丢包率不算特别高,对<code>BBR</code>就几乎没什么影响;当发送速率增长到开始占用缓存区时(这时可以通过延迟的增加判断出来),<code>BBR</code>就及时的放弃了(这时占用的是3倍带宽,相当于有2倍在占用缓存区,但<code>BBR</code>本身还有一个排空阶段,在排空阶段下它会指数降低发送速率),这样就不会把缓存区占满。<br>排空阶段过后就是稳定运行状态,交替探测带宽和延迟,以此来作为基准进行发包。</p><a href="#">Post not found: https://www.zhihu.com/question/53559433 Linux Kernel 4.9 中的 BBR 算法与之前的 TCP 拥塞控制相比有什么优势?</a><h4 id="安装TCP-BBR拥塞算法"><a class="header-anchor" href="#安装TCP-BBR拥塞算法">➡️</a>安装TCP BBR拥塞算法</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat /etc/redhat-release #查看系统版本,输出的release数值大于7.3即可。</span><br></pre></td></tr></table></figure><ol><li>自动安装,使用一键安装脚本</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget --no-check-certificate https://github.com/teddysun/across/raw/master/bbr.sh && chmod +x bbr.sh && ./bbr.sh</span><br></pre></td></tr></table></figure><ol start="2"><li>手动安装</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 使用下面命令安装elrepo并升级内核</span></span><br><span class="line">rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org</span><br><span class="line">rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm</span><br><span class="line">yum --enablerepo=elrepo-kernel install kernel-ml -y</span><br><span class="line"><span class="meta">#</span><span class="bash"> 更新grub文件并重启(reboot后,ssh会断开,稍等一会儿重新连接)</span></span><br><span class="line">egrep ^menuentry /etc/grub2.cfg | cut -f 2 -d \'</span><br><span class="line">grub2-set-default 0</span><br><span class="line">grub2-mkconfig -o /boot/grub2/grub.cfg</span><br><span class="line">reboot</span><br><span class="line"><span class="meta">#</span><span class="bash"> 开机后查看内核是否已经升级</span></span><br><span class="line">uname -r</span><br><span class="line"><span class="meta">#</span><span class="bash"> 启动BBR</span></span><br><span class="line">echo "net.core.default_qdisc = fq" >> /etc/sysctl.conf</span><br><span class="line">echo "net.ipv4.tcp_congestion_control = bbr" >> /etc/sysctl.conf</span><br><span class="line">sysctl -p </span><br></pre></td></tr></table></figure><p>验证bbr是否已经开启</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sysctl net.ipv4.tcp_available_congestion_control #验证当前TCP控制算法的命令</span><br><span class="line">sysctl net.ipv4.tcp_congestion_control #验证BBR是否已经启动</span><br><span class="line">lsmod | grep bbr #返回值有 tcp_bbr 模块即说明 bbr 已启动。</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h4 id="认识BBR拥塞算法"><a class="header-anchor" href="#认识BBR拥塞算法">➡️</a>认识BBR拥塞算法</h4>
<p>从 4.9 开始,Linux 内核已经用上了该算法。根据以往的传统,Google 总是先在自家的生产环境上线运用后,才会将代码开源,此次也不例外。<br>
根据实地测试,在部署了最新版内核并开启了 TCP BBR 的机器上,网速甚至可以提升好几个数量级。</p>
</summary>
<category term="Linux" scheme="https://hexo.lilis.xin/tags/Linux/"/>
<category term="CentOS" scheme="https://hexo.lilis.xin/tags/CentOS/"/>
<category term="TCP" scheme="https://hexo.lilis.xin/tags/TCP/"/>
<category term="BBR" scheme="https://hexo.lilis.xin/tags/BBR/"/>
<category term="拥塞算法" scheme="https://hexo.lilis.xin/tags/%E6%8B%A5%E5%A1%9E%E7%AE%97%E6%B3%95/"/>
</entry>
<entry>
<title>Docker学习笔记</title>
<link href="https://hexo.lilis.xin/posts/6b8adabf/"/>
<id>https://hexo.lilis.xin/posts/6b8adabf/</id>
<published>2019-09-20T01:42:31.000Z</published>
<updated>2019-09-26T03:05:52.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><h3 id="了解-Docker"><a class="header-anchor" href="#了解-Docker">➡️</a>了解 Docker</h3><blockquote><p><code>Docker</code> 最初是 <code>dotCloud</code> 公司创始人 <code>Solomon Hykes</code> 在法国期间发起的一个公司内部项目,它是基于 <code>dotCloud</code> 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 <code>GitHub</code> 上进行维护。<code>Docker</code> 项目后来还加入了 <code>Linux基金会</code>,并成立推动 开放容器联盟(OCI)。</p><a id="more"></a><p><code>Docker</code> 自开源后受到广泛的关注和讨论,至今其 <code>GitHub</code> 项目 已经超过 5 万 2 千个星标和一万多个 <code>fork</code>。甚至由于 <code>Docker</code> 项目的火爆,在 2013 年底,<code>dotCloud</code> 公司决定改名为 <code>Docker</code>。<code>Docker</code> 最初是在 <code>Ubuntu 12.04</code> 上开发实现的;<code>Red Hat</code> 则从 <code>RHEL 6.5</code> 开始对 <code>Docker</code> 进行支持;<code>Google</code> 也在其 <code>PaaS</code> 产品中广泛应用 <code>Docker</code>。<br><code>Docker</code> 使用 <code>Google</code> 公司推出的 <code>Go</code> 语言 进行开发实现,基于 <code>Linux</code> 内核的 <code>cgroup</code>,<code>namespace</code>,以及 <code>AUFS</code> 类的 <code>Union FS</code> 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 <code>LXC</code>,从 <code>0.7</code> 版本以后开始去除 <code>LXC</code>,转而使用自行开发的 <code>libcontainer</code>,从 <code>1.11</code> 开始,则进一步演进为使用 <code>runC</code> 和 <code>containerd</code>。</p><footer><strong>Docker — 从入门到实践</strong><cite><a href="https://yeasy.gitbooks.io/docker_practice/introduction/what.html">什么是 Docker</a></cite></footer></blockquote><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/84118f50.png " class="full-image" title="Docker 架构"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><h3 id="Docker-生命周期"><a class="header-anchor" href="#Docker-生命周期">➡️</a>Docker 生命周期</h3><p>Docker 包括三个基本概念</p><ul><li>镜像(Image)</li><li>容器(Container)</li><li>仓库(Repository)</li></ul><p>容器是由镜像实例化而来的,可以理解成容器是镜像的基础备份,当Docker实例化一个容器时,相当于把这个镜像备份一份,然后在这个备份的基础上启动,开始各种操作。<br>我们可以把镜像想象成类,把容器想象成类经过实例化后的对象。</p><h4 id="Docker-镜像"><a class="header-anchor" href="#Docker-镜像">➡️</a>Docker 镜像</h4><p><code>Docker</code>的镜像概念类似于虚拟机里的镜像,是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器。<br>例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了Mysql或用户需要的其它应用程序。<br><code>Docker</code>的镜像实际上由一层一层的文件系统组成,这种层级的文件系统被称为UnionFS。镜像可以基于<code>Dockerfile</code>构建,<code>Dockerfile</code>是一个描述文件,里面包含若干条命令,每条命令都会对基础文件系统创建新的层次结构。<br><code>Docker</code>提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。</p><div class="note info"><p>注:镜像是只读的,可以理解为静态文件。</p></div><p>镜像是一堆<code>只读层(read-only layer)</code>的统一视角,那些<code>只读层</code>重叠在一起。除了最下面一层,其它层都会有一个指针指向下一层。这些层是<code>Docker</code>内部的实现细节,并且能够在主机(运行<code>Docker</code>的机器)的文件系统上访问到。<code>统一文件系统(union file system)</code>技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。</p><div class="note info"><p>注:<code>Docker</code>在linux上共享内核,无需虚拟化,完全支持native功能。<br><code>Docker</code>在windows上,启用<code>Hyper-V</code>或者<code>虚拟化技术</code>,通过虚拟机来实现,不共享windows内核。<br><code>Docker</code>在macOS上,同样用虚拟化技术<code>xhyve</code>或者<code>virtualbox</code>来实现,不共享macOS内核。<br>所以,在macOS和Windows下是无法直接访问到镜像的文件的。</p></div><h4 id="Docker-容器"><a class="header-anchor" href="#Docker-容器">➡️</a>Docker 容器</h4><p><code>Docker</code>利用容器来运行应用。<br><code>容器(container)</code>和<code>镜像(image)</code>的几乎一样,区别就是<code>容器</code>的最上面一层是可读写的</p><div class="note info"><p>注:相对于镜像来说容器是动态的,容器在启动的时候创建一层可写层作为最上层。<br>容器的定义并没有提及容器是否在运行。</p></div><h5 id="Running-Container-Definition"><a class="header-anchor" href="#Running-Container-Definition">➡️</a>Running Container Definition</h5><p>一个<code>运行态容器(running container)</code>被定义为一个可读写的统一文件系统加上隔离的进程空间和包含其中的进程。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/1ccc2aa9e11e25e5ed2efd18cf1052c4.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p>一个容器中的进程对着个容器里的文件进行增加,删除,修改操作都将作用于容器中最上面的那一层可读写层。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/a20b70e3e4ca61faa2c3436e1bb2d93a.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><h5 id="Image-Layer-Definition"><a class="header-anchor" href="#Image-Layer-Definition">➡️</a>Image Layer Definition</h5><p><code>镜像层(image layer)</code>表示一层中的各种零零星星的数据,它并不仅仅包含文件系统的改变,还能包含了其他重要信息。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/39fb0f8e630b338bcca7a29da3acabb7.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>元数据(metadata)</code>就是关于这个层的额外信息,它不仅能够让<code>Docker</code>获取运行和构建时的信息,还包括父层的层次信息。需要注意,只读层和读写层都包含元数据。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/f3218a8fcdd1fd8bcd5a719ca3c64f59.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p>除此之外,每一层都包括了一个指向父层的指针。如果一个层没有这个指针,说明它处于最底层。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/53e377deeeb5f30bf939ed0836f851c9.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><h4 id="Docker-仓库"><a class="header-anchor" href="#Docker-仓库">➡️</a>Docker 仓库</h4><p>如果你使用过git和github就很容易理解Docker的仓库概念。Docker 仓库的概念跟Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。<br>Docker 仓库是用来包含镜像的位置,Docker提供一个注册服务器(Register)来保存多个仓库,每个仓库又可以包含多个具备不同tag的镜像。Docker运行中使用的默认仓库是 Docker Hub 公共仓库。<br>仓库支持的操作类似git,当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。</p><h4 id="全局理解(Tying-It-All-Together)"><a class="header-anchor" href="#全局理解(Tying-It-All-Together)">➡️</a>全局理解(Tying It All Together)</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker create <image-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/062e7af0929dd205b2ac6efdd937d6f4.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker create</code>命令为指定的<code>镜像(image)</code>创建了一个可读可写层,构成了一个新的容器。注意,这个容器并没有运行。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/162f02c6f9dce4ccdaa0c6c676da2196.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker start <container-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/1c38d4735e9760bdca025ff50a1b5386.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>Docker start</code>命令为容器文件系统创建了一个进程隔离空间。注意,每一个容器只能够有一个进程隔离空间。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run <image-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/01aedf55bd21abbe607b3864d76f0ec0.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker start</code>和<code>docker run</code>命令的区别。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/275cc486d4ce7ecbdecf0ecc1de0a34b.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p>从图片可以看出,<code>docker run</code>命令先是利用镜像创建了一个容器,然后运行这个容器。这个命令非常的方便,并且隐藏了两个命令的细节,但从另一方面来看,这容易让用户产生误解。</p><div class="note info"><p>注:<code>docker run</code>相当于<code>docker create</code>和<code>docker start</code>两个命令的组合。</p></div><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker ps</span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/f05a2a8dfc6641d8237306ff575aa283.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker ps</code>命令会列出所有运行中的容器。这隐藏了非运行态容器的存在。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker ps –a</span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/d7f7b0ada7fc1c641c90745a959f9c05.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker ps –a</code>命令会列出所有的容器,不管是运行的,还是停止的。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker images</span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/d5b0b3e2e7acdcf35e7577d7670a46f7.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker images</code>命令会列出了所有<code>顶层(top-level)镜像</code>。实际上,在这里我们没有办法区分一个镜像和一个只读层,所以我们提出了<code>top-level镜像</code>。只有创建容器时使用的镜像或者是直接pull下来的镜像能被称为<code>顶层(top-level)镜像</code>,并且每一个顶层镜像下面都隐藏了多个镜像层。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker images –a</span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/ce083575e95a0e46b105c3596c12ca71.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker images –a</code>命令列出了所有的镜像,也可以说是列出了所有的可读层。如果你想要查看某一个<code>image-id</code>下的所有层,可以使用<code>docker history</code>来查看。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker stop <container-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/a41de8fe542efe25e3620691ad9238df.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker stop</code>命令会向运行中的容器发送一个<code>SIGTERM</code>的信号,然后停止所有的进程。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker kill <container-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/ac1cbc31d4f191e26e05fb1a11f04d26.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker kill</code>命令向所有运行在容器中的进程发送了一个不友好的<code>SIGKILL</code>信号。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pause <container-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/b701a3c51e7d1915da3bea0bc43efcd1.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker stop</code>和<code>docker kill</code>命令会发送UNIX的信号给运行中的进程,<code>docker pause</code>命令则不一样,它利用了<code>cgroups</code>的特性将运行中的进程空间暂停。但是这种方式的不足之处在于发送一个<code>SIGTSTP</code>信号对于进程来说不够简单易懂,以至于不能够让所有进程暂停。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker rm <container-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/8fa2d6e19c29f18548624efd64eb6dfa.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker rm</code>命令会移除构成容器的可读写层。注意,这个命令只能对非运行态容器执行。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker rmi <image-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/32a7f413a5f8ff936dd0f4a31d25fdcc.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker rmi</code>命令会移除构成镜像的一个只读层。你只能够使用<code>docker rmi</code>来移除<code>最顶层(top level layer)</code>(也可以说是镜像),你也可以使用<code>-f</code>参数来强制删除中间的只读层。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker commit <container-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/3c02ccf4e7a2a353af065d93b26ae89e.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker commit</code>命令将容器的可读写层转换为一个只读层,这样就把一个容器转换成了不可变的镜像。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/28059b3a499faba896263c0ff077fe3a.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker build</span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/b22cd304f28c715ae3ae6812476b222d.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker build</code>命令会反复的执行多个命令。</p><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/100712263ecf4544dd11602adc39ee3e.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>build</code>命令根据<code>Dockerfile</code>文件中的<code>FROM</code>指令获取到镜像,然后重复地</p><ol><li><code>run(create和start)</code></li><li>修改</li><li>commit</li></ol><p>在循环中的每一步都会生成一个新的层,因此许多新的层会被创建。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker exec <running-container-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/db64b3b38aff136d42e9ffeb81675bda.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker exec</code>命令会在运行中的容器执行一个新进程</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker inspect <container-id> or <image-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/184f9d55770ca036cb5b1e6d96ce4a12.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker inspect</code>命令会提取出容器或者镜像最顶层的元数据。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker save <image-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/70cdbaf975c88bc83423d88be85476b5.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker save</code>命令会创建一个镜像的压缩文件,这个文件能够在另外一个主机的<code>Docker</code>上使用。和<code>export</code>命令不同,这个命令为每一个层都保存了它们的元数据。这个命令只能对镜像生效。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker export <container-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/1714c3dd524c807bf9c9b4d0fbe4d056.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker export</code>命令创建一个tar文件,并且移除了元数据和不必要的层,将多个层整合成了一个层,只保存了当前统一视角看到的内容。</p><div class="note info"><p>注:<code>expoxt</code>后的容器再<code>import</code>到<code>Docker</code>中,通过<code>docker images –tree</code>命令只能看到一个镜像;而<code>save</code>后的镜像则不同,它能够看到这个镜像的历史镜像。</p></div><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker history <image-id></span><br></pre></td></tr></table></figure><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="images/b513dd5467f23fdd23523f60242d5dcb.png" class="full-image"><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><p><code>docker history</code>命令递归地输出指定镜像的历史镜像。</p><div class="note info"><p>参考链接:</p><ul><li><a href="https://merrigrove.blogspot.com/2015/10/visualizing-docker-containers-and-images.html" title="Visualizing Docker Containers and Images" target>Visualizing Docker Containers and Images</a></li><li><a href="http://dockone.io/article/783" title="10张图带你深入理解Docker容器和镜像" target>10张图带你深入理解Docker容器和镜像</a></li></ul></div><h3 id="Docker-命令"><a class="header-anchor" href="#Docker-命令">➡️</a>Docker 命令</h3><a href="https://www.runoob.com/docker/docker-command-manual.html" title="Docker 命令大全" target>参考链接</a><h4 id="Docker-run"><a class="header-anchor" href="#Docker-run">➡️</a>Docker run</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run [OPTIONS] IMAGE [COMMAND] [ARG...]</span><br></pre></td></tr></table></figure><p>OPTIONS说明:</p><ul><li>-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;</li><li>-d: 后台运行容器,并返回容器ID;</li><li>-i: 以交互模式运行容器,通常与 -t 同时使用;</li><li>-P: 随机端口映射,容器内部端口随机映射到主机的高端口</li><li>-p: 指定端口映射,格式为:主机(宿主)端口:容器端口</li><li>-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;</li><li>–name=“nginx-lb”: 为容器指定一个名称;</li><li>–dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;</li><li>–dns-search <a href="http://example.com">example.com</a>: 指定容器DNS搜索域名,默认和宿主一致;</li><li>-h “mars”: 指定容器的hostname;</li><li>-e username=“ritchie”: 设置环境变量;</li><li>–env-file=[]: 从指定文件读入环境变量;</li><li>–cpuset=“0-2” or --cpuset=“0,1,2”: 绑定容器到指定CPU运行;</li><li>-m :设置容器使用内存最大值;</li><li>–net=“bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;</li><li>–link=[]: 添加链接到另一个容器;</li><li>–expose=[]: 开放一个端口或一组端口;</li><li>–volume , -v: 绑定一个卷</li></ul><p>实例:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 使用docker镜像nginx:latest以后台模式启动一个容器,并将容器命名为mynginx。</span></span><br><span class="line">docker run --name mynginx -d nginx:latest</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 使用镜像nginx:latest以后台模式启动一个容器,并将容器的80端口映射到主机随机端口。</span></span><br><span class="line">docker run -P -d nginx:latest</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 使用镜像 nginx:latest,以后台模式启动一个容器,将容器的 80 端口映射到主机的 80 端口,主机的目录 /data 映射到容器的 /data。</span></span><br><span class="line">docker run -p 80:80 -v /data:/data -d nginx:latest</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 绑定容器的 8080 端口,并将其映射到本地主机 127.0.0.1 的 80 端口上。</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> docker run -p 127.0.0.1:80:8080/tcp ubuntu bash</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 使用镜像nginx:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。</span></span><br><span class="line">runoob@runoob:~$ docker run -it nginx:latest /bin/bash</span><br><span class="line">root@b85456f75:/# </span><br></pre></td></tr></table></figure><h4 id="Docker-start-stop-restart-命令"><a class="header-anchor" href="#Docker-start-stop-restart-命令">➡️</a>Docker start/stop/restart 命令</h4><p><code>docker start</code> :启动一个或多个已经被停止的容器<br><code>docker stop</code> :停止一个运行中的容器<br><code>docker restart</code> :重启容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker start [OPTIONS] CONTAINER [CONTAINER...]</span><br><span class="line">docker stop [OPTIONS] CONTAINER [CONTAINER...]</span><br><span class="line">docker restart [OPTIONS] CONTAINER [CONTAINER...]</span><br></pre></td></tr></table></figure><p>实例:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 启动已被停止的容器myrunoob</span></span><br><span class="line">docker start myrunoob</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 停止运行中的容器myrunoob</span></span><br><span class="line">docker stop myrunoob</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 重启容器myrunoob</span></span><br><span class="line">docker restart myrunoob</span><br></pre></td></tr></table></figure><h4 id="Docker-attach-命令"><a class="header-anchor" href="#Docker-attach-命令">➡️</a>Docker attach 命令</h4><p><code>docker attach</code>:连接到正在运行中的容器。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker attach [OPTIONS] CONTAINER</span><br></pre></td></tr></table></figure><p>要attach上去的容器必须正在运行,可以同时连接上同一个container来共享屏幕(与screen命令的attach类似)。<br>官方文档中说attach后可以通过CTRL-C来detach,但实际上经过我的测试,如果container当前在运行bash,CTRL-C自然是当前行的输入,没有退出;如果container当前正在前台运行进程,如输出nginx的access.log日志,CTRL-C不仅会导致退出容器,而且还stop了。这不是我们想要的,detach的意思按理应该是脱离容器终端,但容器依然运行。好在attach是可以带上–sig-proxy=false来确保CTRL-D或CTRL-C不会关闭容器。</p><h4 id="Docker-create-命令"><a class="header-anchor" href="#Docker-create-命令">➡️</a>Docker create 命令</h4><p>创建一个新的容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker create [OPTIONS] IMAGE [COMMAND] [ARG...]</span><br></pre></td></tr></table></figure><h5 id="Options"><a class="header-anchor" href="#Options">➡️</a>Options</h5><table><thead><tr><th>Name,shorthand</th><th style="text-align:center">Default</th><th>Description</th></tr></thead><tbody><tr><td>–add-host</td><td style="text-align:center"></td><td>Add a custom host-to-IP mapping (host:ip)</td></tr><tr><td>–attach , -a</td><td style="text-align:center"></td><td>Attach to STDIN, STDOUT or STDERR</td></tr><tr><td>–blkio-weight</td><td style="text-align:center"></td><td>Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)</td></tr><tr><td>–blkio-weight-device</td><td style="text-align:center"></td><td>Block IO weight (relative device weight)</td></tr><tr><td>–cap-add</td><td style="text-align:center"></td><td>Add Linux capabilities</td></tr><tr><td>–cap-drop</td><td style="text-align:center"></td><td>Drop Linux capabilities</td></tr><tr><td>–cgroup-parent</td><td style="text-align:center"></td><td>Optional parent cgroup for the container</td></tr><tr><td>–cidfile</td><td style="text-align:center"></td><td>Write the container ID to the file</td></tr><tr><td>–cpu-count</td><td style="text-align:center"></td><td>CPU count (Windows only)</td></tr><tr><td>–cpu-percent</td><td style="text-align:center"></td><td>CPU percent (Windows only)</td></tr><tr><td>–cpu-period</td><td style="text-align:center"></td><td>Limit CPU CFS (Completely Fair Scheduler) period</td></tr><tr><td>–cpu-quota</td><td style="text-align:center"></td><td>Limit CPU CFS (Completely Fair Scheduler) quota</td></tr><tr><td>–cpu-rt-period</td><td style="text-align:center"></td><td><code>API 1.25+</code><br>Limit CPU real-time period in microseconds</td></tr><tr><td>–cpu-rt-runtime</td><td style="text-align:center"></td><td><code>API 1.25+</code><br>Limit CPU real-time runtime in microseconds</td></tr><tr><td>–cpu-shares , -c</td><td style="text-align:center"></td><td>CPU shares (relative weight)</td></tr><tr><td>–cpus</td><td style="text-align:center"></td><td><code>API 1.25+</code><br>Number of CPUs</td></tr><tr><td>–cpuset-cpus</td><td style="text-align:center"></td><td>CPUs in which to allow execution (0-3, 0,1)</td></tr><tr><td>–cpuset-mems</td><td style="text-align:center"></td><td>MEMs in which to allow execution (0-3, 0,1)</td></tr><tr><td>–device</td><td style="text-align:center"></td><td>Add a host device to the container</td></tr><tr><td>–device-cgroup-rule</td><td style="text-align:center"></td><td>Add a rule to the cgroup allowed devices list</td></tr><tr><td>–device-read-bps</td><td style="text-align:center"></td><td>Limit read rate (bytes per second) from a device</td></tr><tr><td>–device-read-iops</td><td style="text-align:center"></td><td>Limit read rate (IO per second) from a device</td></tr><tr><td>–device-write-bps</td><td style="text-align:center"></td><td>Limit write rate (bytes per second) to a device</td></tr><tr><td>–device-write-iops</td><td style="text-align:center"></td><td>Limit write rate (IO per second) to a device</td></tr><tr><td>–disable-content-trust</td><td style="text-align:center">true</td><td>Skip image verification</td></tr><tr><td>–dns</td><td style="text-align:center"></td><td>Set custom DNS servers</td></tr><tr><td>–dns-opt</td><td style="text-align:center"></td><td>Set DNS options</td></tr><tr><td>–dns-option</td><td style="text-align:center"></td><td>Set DNS options</td></tr><tr><td>–dns-search</td><td style="text-align:center"></td><td>Set custom DNS search domains</td></tr><tr><td>–domainname</td><td style="text-align:center"></td><td>Container NIS domain name</td></tr><tr><td>–entrypoint</td><td style="text-align:center"></td><td>Overwrite the default ENTRYPOINT of the image</td></tr><tr><td>–env , -e</td><td style="text-align:center"></td><td>Set environment variables</td></tr><tr><td>–env-file</td><td style="text-align:center"></td><td>Read in a file of environment variables</td></tr><tr><td>–expose</td><td style="text-align:center"></td><td>Expose a port or a range of ports</td></tr><tr><td>–gpus</td><td style="text-align:center"></td><td><code>API 1.40+</code><br>GPU devices to add to the container (‘all’ to pass all GPUs)</td></tr><tr><td>–group-add</td><td style="text-align:center"></td><td>Add additional groups to join</td></tr><tr><td>–health-cmd</td><td style="text-align:center"></td><td>Command to run to check health</td></tr><tr><td>–health-interval</td><td style="text-align:center"></td><td>Time between running the check (ms丨s丨m丨h) (default 0s)</td></tr><tr><td>–health-retries</td><td style="text-align:center"></td><td>Consecutive failures needed to report unhealthy</td></tr><tr><td>–health-start-period</td><td style="text-align:center"></td><td><code>API 1.29+</code><br>Start period for the container to initialize before starting health-retries countdown (ms丨s&丨m丨h) (default 0s)</td></tr><tr><td>–health-timeout</td><td style="text-align:center"></td><td>Maximum time to allow one check to run (ms丨s丨m丨h) (default 0s)</td></tr><tr><td>–help</td><td style="text-align:center"></td><td>Print usage</td></tr><tr><td>–hostname , -h</td><td style="text-align:center"></td><td>Container host name</td></tr><tr><td>–init</td><td style="text-align:center"></td><td><code>API 1.25+</code><br>Run an init inside the container that forwards signals and reaps processes</td></tr><tr><td>–interactive , -i</td><td style="text-align:center"></td><td>Keep STDIN open even if not attached</td></tr><tr><td>–io-maxbandwidth</td><td style="text-align:center"></td><td>Maximum IO bandwidth limit for the system drive (Windows only)</td></tr><tr><td>–io-maxiops</td><td style="text-align:center"></td><td>Maximum IOps limit for the system drive (Windows only)</td></tr><tr><td>–ip</td><td style="text-align:center"></td><td>IPv4 address (e.g., 172.30.100.104)</td></tr><tr><td>–ip6</td><td style="text-align:center"></td><td>IPv6 address (e.g., 2001:db8::33)</td></tr><tr><td>–ipc</td><td style="text-align:center"></td><td>IPC mode to use</td></tr><tr><td>–isolation</td><td style="text-align:center"></td><td>Container isolation technology</td></tr><tr><td>–kernel-memory</td><td style="text-align:center"></td><td>Kernel memory limit</td></tr><tr><td>–label , -l</td><td style="text-align:center"></td><td>Set meta data on a container</td></tr><tr><td>–label-file</td><td style="text-align:center"></td><td>Read in a line delimited file of labels</td></tr><tr><td>–link</td><td style="text-align:center"></td><td>Add link to another container</td></tr><tr><td>–link-local-ip</td><td style="text-align:center"></td><td>Container IPv4/IPv6 link-local addresses</td></tr><tr><td>–log-driver</td><td style="text-align:center"></td><td>Logging driver for the container</td></tr><tr><td>–log-opt</td><td style="text-align:center"></td><td>Log driver options</td></tr><tr><td>–mac-address</td><td style="text-align:center"></td><td>Container MAC address (e.g., 92:d0:c6:0a:29:33)</td></tr><tr><td>–memory , -m</td><td style="text-align:center"></td><td>Memory limit</td></tr><tr><td>–memory-reservation</td><td style="text-align:center"></td><td>Memory soft limit</td></tr><tr><td>–memory-swap</td><td style="text-align:center"></td><td>Swap limit equal to memory plus swap: ‘-1’ to enable unlimited swap</td></tr><tr><td>–memory-swappiness</td><td style="text-align:center">-1</td><td>Tune container memory swappiness (0 to 100)</td></tr><tr><td>–mount</td><td style="text-align:center"></td><td>Attach a filesystem mount to the container</td></tr><tr><td>–name</td><td style="text-align:center"></td><td>Assign a name to the container</td></tr><tr><td>–net</td><td style="text-align:center"></td><td>Connect a container to a network</td></tr><tr><td>–net-alias</td><td style="text-align:center"></td><td>Add network-scoped alias for the container</td></tr><tr><td>–network</td><td style="text-align:center"></td><td>Connect a container to a network</td></tr><tr><td>–network-alias</td><td style="text-align:center"></td><td>Add network-scoped alias for the container</td></tr><tr><td>–no-healthcheck</td><td style="text-align:center"></td><td>Disable any container-specified HEALTHCHECK</td></tr><tr><td>–oom-kill-disable</td><td style="text-align:center"></td><td>Disable OOM Killer</td></tr><tr><td>–oom-score-adj</td><td style="text-align:center"></td><td>Tune host’s OOM preferences (-1000 to 1000)</td></tr><tr><td>–pid</td><td style="text-align:center"></td><td>PID namespace to use</td></tr><tr><td>–pids-limit</td><td style="text-align:center"></td><td>Tune container pids limit (set -1 for unlimited)</td></tr><tr><td>–platform</td><td style="text-align:center"></td><td><code>experimental (daemon)API 1.32+</code><br>Set platform if server is multi-platform capable</td></tr><tr><td>–privileged</td><td style="text-align:center"></td><td>Give extended privileges to this container</td></tr><tr><td>–publish , -p</td><td style="text-align:center"></td><td>Publish a container’s port(s) to the host</td></tr><tr><td>–publish-all , -P</td><td style="text-align:center"></td><td>Publish all exposed ports to random ports</td></tr><tr><td>–read-only</td><td style="text-align:center"></td><td>Mount the container’s root filesystem as read only</td></tr><tr><td>–restart</td><td style="text-align:center">no</td><td>Restart policy to apply when a container exits</td></tr><tr><td>–rm</td><td style="text-align:center"></td><td>Automatically remove the container when it exits</td></tr><tr><td>–runtime</td><td style="text-align:center"></td><td>Runtime to use for this container</td></tr><tr><td>–security-opt</td><td style="text-align:center"></td><td>Security Options</td></tr><tr><td>–shm-size</td><td style="text-align:center"></td><td>Size of /dev/shm</td></tr><tr><td>–stop-signal</td><td style="text-align:center">SIGTERM</td><td>Signal to stop a container</td></tr><tr><td>–stop-timeout</td><td style="text-align:center"></td><td><code>API 1.25+</code><br>Timeout (in seconds) to stop a container</td></tr><tr><td>–storage-opt</td><td style="text-align:center"></td><td>Storage driver options for the container</td></tr><tr><td>–sysctl</td><td style="text-align:center"></td><td>Sysctl options</td></tr><tr><td>–tmpfs</td><td style="text-align:center"></td><td>Mount a tmpfs directory</td></tr><tr><td>–tty , -t</td><td style="text-align:center"></td><td>Allocate a pseudo-TTY</td></tr><tr><td>–ulimit</td><td style="text-align:center"></td><td>Ulimit options</td></tr><tr><td>–user , -u</td><td style="text-align:center"></td><td>Username or UID (format: <name丨uid>[:<group丨gid>])</td></tr><tr><td>–userns</td><td style="text-align:center"></td><td>User namespace to use</td></tr><tr><td>–uts</td><td style="text-align:center"></td><td>UTS namespace to use</td></tr><tr><td>–volume , -v</td><td style="text-align:center"></td><td>Bind mount a volume</td></tr><tr><td>–volume-driver</td><td style="text-align:center"></td><td>Optional volume driver for the container</td></tr><tr><td>–volumes-from</td><td style="text-align:center"></td><td>Mount volumes from the specified container(s)</td></tr><tr><td>–workdir , -w</td><td style="text-align:center"></td><td>Working directory inside the container</td></tr></tbody></table>]]></content>
<summary type="html">
<h3 id="了解-Docker"><a class="header-anchor" href="#了解-Docker">➡️</a>了解 Docker</h3>
<blockquote><p><code>Docker</code> 最初是 <code>dotCloud</code> 公司创始人 <code>Solomon Hykes</code> 在法国期间发起的一个公司内部项目,它是基于 <code>dotCloud</code> 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 <code>GitHub</code> 上进行维护。<code>Docker</code> 项目后来还加入了 <code>Linux基金会</code>,并成立推动 开放容器联盟(OCI)。</p></blockquote>
</summary>
<category term="linux" scheme="https://hexo.lilis.xin/tags/linux/"/>
<category term="docker" scheme="https://hexo.lilis.xin/tags/docker/"/>
<category term="虚拟化" scheme="https://hexo.lilis.xin/tags/%E8%99%9A%E6%8B%9F%E5%8C%96/"/>
</entry>
<entry>
<title>hexo 配置gitalk</title>
<link href="https://hexo.lilis.xin/posts/44125ab6/"/>
<id>https://hexo.lilis.xin/posts/44125ab6/</id>
<published>2019-09-13T05:33:39.000Z</published>
<updated>2019-09-13T07:37:02.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>我现在用的博客是静态网页,没有独立的后端服务器来支撑,为了实现评论功能,需要对接第三方的评论插件,经过各种考虑,决定使用<code>gitalk</code>。<br>这是一个基于<code>GitHub</code>的<code>issues</code>来实现的评论工具。</p><a id="more"></a><p>这个功能使用到了以下插件</p><div style="text-align: center"> <div class="github-card" data-user="gitalk" data-repo="gitalk" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script><div style="text-align: center"> <div class="github-card" data-user="blueimp" data-repo="JavaScript-MD5" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script><h4 id="GitHub"><a class="header-anchor" href="#GitHub">➡️</a>GitHub</h4><p>首先得有一个<code>GitHub</code>账号,然后打开链接↙️<br><a href="https://github.com/settings/applications/new">New OAuth application</a><br>注册一个<code>OAuth App</code><br>具体填写参考如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Application name //应用名称</span><br><span class="line">Homepage URL //填自己的博客地址就可以了</span><br><span class="line">Application description //应用描述</span><br><span class="line">Authorization callback URL //填写自己要用 gitalk 的博客地址</span><br></pre></td></tr></table></figure><p>在这里填写完成之后你就会得到<code>Client ID</code>和<code>Client Secret</code>。</p><h4 id="文件修改"><a class="header-anchor" href="#文件修改">➡️</a>文件修改</h4><p>在主题目录下建立<code>/layout/_third-party/gitalk.swig</code>文件并添加以下代码</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">{% if page.comments && theme.gitalk.enable %}</span><br><span class="line"></span><br><span class="line"> <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css"></span><br><span class="line"> <script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script></span><br><span class="line"> <script src="https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js"></script></span><br><span class="line"></span><br><span class="line"> <script type="text/javascript"></span><br><span class="line"> var gitalk = new Gitalk({</span><br><span class="line"> clientID: '{{ theme.gitalk.ClientID }}',</span><br><span class="line"> clientSecret: '{{ theme.gitalk.ClientSecret }}',</span><br><span class="line"> repo: '{{ theme.gitalk.repo }}',</span><br><span class="line"> owner: '{{ theme.gitalk.owner }}',</span><br><span class="line"> admin: '{{ theme.gitalk.adminUser }}',</span><br><span class="line"> id: md5({{ theme.gitalk.ID }}),</span><br><span class="line"> labels: {{ theme.gitalk.labels }},</span><br><span class="line"> perPage: {{ theme.gitalk.perPage }},</span><br><span class="line"> pagerDirection: '{{ theme.gitalk.pagerDirection }}',</span><br><span class="line"> createIssueManually: {{ theme.gitalk.createIssueManually }},</span><br><span class="line"> distractionFreeMode: {{ theme.gitalk.distractionFreeMode }}</span><br><span class="line"> })</span><br><span class="line"> gitalk.render('gitalk-container')</span><br><span class="line"> </script></span><br><span class="line">{% endif %}</span><br></pre></td></tr></table></figure><p>在主题的<code>/layout/_scripts/commons.swig</code>中添加以下代码</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{% include '../_third-party/comments/gitalk.swig' %}</span><br></pre></td></tr></table></figure><p>接着,在主题的<code>/layout/_partials/comments.swig</code>中找到</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">{% elseif theme.valine.appid and theme.valine.appkey %}</span><br><span class="line"> <div class="comments" id="comments"></span><br><span class="line"> </div></span><br><span class="line">{% endif %}</span><br></pre></td></tr></table></figure><p>并添加以下代码</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">{% if theme.gitalk.enable %}</span><br><span class="line"> <div id="gitalk-container"></div></span><br><span class="line">{% endif %}</span><br></pre></td></tr></table></figure><h4 id="进行配置"><a class="header-anchor" href="#进行配置">➡️</a>进行配置</h4><p>在主题的配置文件中,添加一下内容</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">gitalk:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span> <span class="comment"># 是否启动</span></span><br><span class="line"> <span class="attr">ClientID:</span> <span class="string">xxxxxx</span> <span class="comment"># 之前的Client ID</span></span><br><span class="line"> <span class="attr">ClientSecret:</span> <span class="string">xxxxxxxxxxxx</span> <span class="comment"># 之前的Client Secret</span></span><br><span class="line"> <span class="attr">repo:</span> <span class="string">gitalk</span> <span class="comment"># 留言板内容需要存放的仓库名称</span></span><br><span class="line"> <span class="attr">owner:</span> <span class="string">l552121229</span> <span class="comment"># 你 github 的帐号 eg: www.github.com/zhongxia245 ,帐号就是245</span></span><br><span class="line"> <span class="attr">adminUser:</span> [<span class="string">'l552121229'</span>] <span class="comment"># 管理员用户</span></span><br><span class="line"> <span class="attr">ID:</span> <span class="string">location.pathname</span></span><br><span class="line"> <span class="attr">labels:</span> <span class="string">'["gitalk"]'</span> <span class="comment"># issue 的标签</span></span><br><span class="line"> <span class="attr">perPage:</span> <span class="number">15</span> <span class="comment"># 每页展示条数</span></span><br><span class="line"> <span class="attr">pagerDirection:</span> <span class="string">last</span> <span class="comment"># 排序方式是从旧到新(first)还是从新到旧(last)</span></span><br><span class="line"> <span class="attr">createIssueManually:</span> <span class="literal">true</span> <span class="comment">#如果当前页面没有相应的 isssue ,且登录的用户属于 admin,则会自动创建 issue。如果设置为 true,则显示一个初始化页面,创建 issue 需要点击 init 按钮。</span></span><br><span class="line"> <span class="attr">distractionFreeMode:</span> <span class="literal">true</span> <span class="comment">#是否启用快捷键(cmd|ctrl + enter) 提交评论.</span></span><br></pre></td></tr></table></figure><ul><li>因为我们上面配置的<code>gitalk</code>是用<code>location.pathname</code>来作为项目标签区分的,如果这个文章名超过50个字就会报错,为了保险起见,我们通过引入<code>md5.min.js</code>来防止<code>lables</code>过长。</li></ul>]]></content>
<summary type="html">
<p>我现在用的博客是静态网页,没有独立的后端服务器来支撑,为了实现评论功能,需要对接第三方的评论插件,经过各种考虑,决定使用<code>gitalk</code>。<br>
这是一个基于<code>GitHub</code>的<code>issues</code>来实现的评论工具。</p>
</summary>
<category term="hexo" scheme="https://hexo.lilis.xin/tags/hexo/"/>
<category term="gitalk" scheme="https://hexo.lilis.xin/tags/gitalk/"/>
<category term="评论" scheme="https://hexo.lilis.xin/tags/%E8%AF%84%E8%AE%BA/"/>
<category term="node" scheme="https://hexo.lilis.xin/tags/node/"/>
</entry>
<entry>
<title>hexo 插件</title>
<link href="https://hexo.lilis.xin/posts/54690ca6/"/>
<id>https://hexo.lilis.xin/posts/54690ca6/</id>
<published>2019-09-12T07:45:38.000Z</published>
<updated>2019-10-10T09:15:19.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>搜集整理常用的<code>hexo</code>插件</p><a id="more"></a><h4 id="hexo-helper-live2d"><a class="header-anchor" href="#hexo-helper-live2d">➡️</a>hexo-helper-live2d</h4><p>在hexo博客里增加纸片人</p><div style="text-align: center"> <div class="github-card" data-user="EYHN" data-repo="hexo-helper-live2d" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script><h4 id="hexo-tag-aplayer"><a class="header-anchor" href="#hexo-tag-aplayer">➡️</a>hexo-tag-aplayer</h4><p><code>APlayer</code>播放器的<code>Hexo</code>标签插件</p><div style="text-align: center"> <div class="github-card" data-user="MoePlayer" data-repo="hexo-tag-aplayer" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script><p>效果:</p><div id="aplayer0" class="aplayer" style="margin-bottom: 20px;"></div><script>var options = {"narrow":false,"autoplay":false,"showlrc":3,"mode":"random","mutex":true,"theme":"#e6d0b2","preload":"metadata","listmaxheight":"100%","music":[{"title":"トリカゴ","author":"XX:me","url":"https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3","pic":"https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg","lrc":"https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc"},{"title":"前前前世","author":"RADWIMPS","url":"https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3","pic":"https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg","lrc":"https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc"},{"title":"光るなら","author":"Goose house","url":"https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3","pic":"https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg","lrc":"https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc"}]};options.element = document.getElementById("aplayer0");new APlayer(options);</script><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#安装</span><br><span class="line">yarn add hexo-tag-aplayer</span><br><span class="line">#使用</span><br><span class="line">{% aplayer title author url [picture_url, narrow, autoplay, width:xxx, lrc:xxx] %}</span><br></pre></td></tr></table></figure><p>标签参数</p><ul><li><code>title</code> : 曲目标题</li><li><code>author</code>: 曲目作者</li><li><code>url</code>: 音乐文件 URL 地址</li><li><code>picture_url</code>: (可选) 音乐对应的图片地址</li><li><code>narrow</code>: (可选)播放器袖珍风格</li><li><code>autoplay</code>: (可选) 自动播放,移动端浏览器暂时不支持此功能</li><li><code>width</code>:xxx: (可选) 播放器宽度 (默认: 100%)</li><li><code>lrc</code>:xxx: (可选)歌词文件 URL 地址</li></ul><h4 id="hexo-github-card"><a class="header-anchor" href="#hexo-github-card">➡️</a>hexo-github-card</h4><div style="text-align: center"> <div class="github-card" data-user="Gisonrg" data-repo="hexo-github-card" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script><p>使用这个插件可以像上面这样👆显示逼格较高的GitHub链接<br>使用时只需要插入下面👇这个🏷️就可以了</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">{% githubCard user:your_user [repo:your_repo] [width:400] [height:200] [theme:default] [client_id:your_client_id] [client_secret:your_client_secret] [align:text-align_position] %}</span><br><span class="line">//这是上面那个卡片🏷️</span><br><span class="line">{% githubCard user:Gisonrg repo:hexo-github-card %}</span><br></pre></td></tr></table></figure><p>这个插件的默认宽度感觉有点不够美观,每次使用都需要自定义宽度也有点费事,而且默认打开方式是在当前页面页打开很不人性化,受不了的话可以选择修改文件</p><figure class="highlight javascript"><figcaption><span>node_modules/hexo-github-card/index.js</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> user = argsObj.user,</span><br><span class="line"> repo = argsObj.repo,</span><br><span class="line"> width = argsObj.width || <span class="string">'100%'</span>,<span class="comment">//宽度自适应</span></span><br><span class="line"> height = argsObj.height || <span class="string">'200'</span>,</span><br><span class="line"> theme = argsObj.theme || <span class="string">'default'</span>,</span><br><span class="line"> client_id = argsObj.client_id || <span class="string">''</span>,</span><br><span class="line"> client_secret = argsObj.client_secret || <span class="string">''</span>,</span><br><span class="line"> align = argsObj.align || <span class="string">'center'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> payload = {</span><br><span class="line"> user,</span><br><span class="line"> repo,</span><br><span class="line"> height,</span><br><span class="line"> width,</span><br><span class="line"> theme,</span><br><span class="line"> client_id,</span><br><span class="line"> client_secret,</span><br><span class="line"> style: <span class="string">`text-align: <span class="subst">${align}</span>`</span>,</span><br><span class="line"> target: <span class="string">'blank'</span>,<span class="comment">//加上这个可以在其他标签页打开链接</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>由于直接在原文件上修改,后面再进行<code>yarn</code>的一些相关操作时<code>yarn</code>总是会自动把代码还原回去,<code>yarn</code>还不支持<code>ignore</code>名单功能,我就在原来的插件基础上进行了小的修改,使它的默认值配置更加人性化一点,有需要的小伙伴可以直接看看这个👇</p><div style="text-align: center"> <div class="github-card" data-user="l552121229" data-repo="hexo-github-card-customize" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script><p>这个修改过的插件可以配置默认设置</p><figure class="highlight yaml"><figcaption><span>_config.yml</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">github_card:</span></span><br><span class="line"> <span class="attr">width:</span> <span class="number">100</span><span class="string">%</span></span><br><span class="line"> <span class="attr">height:</span> <span class="string">200px</span></span><br><span class="line"> <span class="attr">theme:</span> <span class="string">default</span></span><br><span class="line"> <span class="attr">align:</span> <span class="string">center</span></span><br><span class="line"> <span class="attr">target:</span> <span class="string">blank</span></span><br></pre></td></tr></table></figure><h4 id="基于next的插件"><a class="header-anchor" href="#基于next的插件">➡️</a>基于<code>next</code>的插件</h4><div class="note warning"><p>我现在使用的<code>next</code>是<code>7.4.0</code>版本的,下面的几个插件都是基于这个版本确认可用的,其他版本需要具体看相应的<code>GitHub</code>链接的说明</p></div><h5 id="theme-next-canvas-nest"><a class="header-anchor" href="#theme-next-canvas-nest">➡️</a>theme-next-canvas-nest</h5><div style="text-align: center"> <div class="github-card" data-user="theme-next" data-repo="theme-next-canvas-nest" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script><p>进入主题目录并clone代码</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd themes/next</span><br><span class="line">git clone https://github.com/theme-next/theme-next-canvas-nest source/lib/canvas-nest</span><br></pre></td></tr></table></figure><p>配置</p><figure class="highlight yaml"><figcaption><span>themes/next/_config.yml</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">canvas_nest:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">onmobile:</span> <span class="literal">true</span> <span class="comment"># display on mobile or not</span></span><br><span class="line"> <span class="attr">color:</span> <span class="string">'0,0,255'</span> <span class="comment"># RGB values, use ',' to separate</span></span><br><span class="line"> <span class="attr">opacity:</span> <span class="number">0.5</span> <span class="comment"># the opacity of line: 0~1</span></span><br><span class="line"> <span class="attr">zIndex:</span> <span class="number">-1</span> <span class="comment"># z-index property of the background</span></span><br><span class="line"> <span class="attr">count:</span> <span class="number">99</span> <span class="comment"># the number of lines</span></span><br></pre></td></tr></table></figure><p>更新</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd themes/next/source/lib/canvas-nest</span><br><span class="line">git pull</span><br></pre></td></tr></table></figure><h5 id="theme-next-pjax"><a class="header-anchor" href="#theme-next-pjax">➡️</a>theme-next-pjax</h5><p>在<code>hexo</code>上使用<code>pjax</code>,优化访问速度,这个插件基于主题<code>next</code>实现</p><div style="text-align: center"> <div class="github-card" data-user="theme-next" data-repo="theme-next-pjax" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script><p>使用</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cd themes/next</span><br><span class="line">git clone https://github.com/theme-next/theme-next-pjax source/lib/pjax</span><br></pre></td></tr></table></figure><p>修改文件</p><figure class="highlight yaml"><figcaption><span>themes/next/_config.yml</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">pjax:</span> <span class="literal">true</span></span><br><span class="line"><span class="string">...</span></span><br><span class="line"><span class="attr">vendors:</span></span><br><span class="line"> <span class="string">...</span></span><br><span class="line"> <span class="attr">pjax:</span> <span class="string">//cdn.jsdelivr.net/gh/theme-next/theme-next-pjax@0/pjax.min.js</span></span><br></pre></td></tr></table></figure><h4 id="比较有意思的git库"><a class="header-anchor" href="#比较有意思的git库">➡️</a>比较有意思的git库</h4><h5 id="91porn-php"><a class="header-anchor" href="#91porn-php">➡️</a>91porn_php</h5><div style="text-align: center"> <div class="github-card" data-user="zzjzz9266a" data-repo="91porn_php" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script>]]></content>
<summary type="html">
<p>搜集整理常用的<code>hexo</code>插件</p>
</summary>
</entry>
<entry>
<title>git本地仓库和裸仓库</title>
<link href="https://hexo.lilis.xin/posts/ac107f22/"/>
<id>https://hexo.lilis.xin/posts/ac107f22/</id>
<published>2019-09-11T09:50:25.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><h4 id="git-初始化"><a class="header-anchor" href="#git-初始化">➡️</a>git 初始化</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git init #git目录初始化</span><br><span class="line">git init <repo> #本地初始化,并且建立一个名为repo的空仓库</span><br><span class="line">git init --bare #git裸仓库初始化</span><br><span class="line">git init --bare <repo> #指定某个目录成为中心仓库(裸仓库)</span><br></pre></td></tr></table></figure><p><code>git init</code>这个命令执行后会在本地生成一个 .git 的文件夹,用来追踪仓库的所有变更。<br><code>--bare</code>: 使用 --bare 参数初始化的仓库,我们一般称之为裸仓库, 因为这样创建的仓库并不包含 工作区 , 也就是说,我们并不能在这个目录下执行我们一般使用的 Git 命令。</p><a id="more"></a><h5 id="对比"><a class="header-anchor" href="#对比">➡️</a>对比</h5><ul><li>直接 git init 创建的仓库:</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[core]</span><br><span class="line">repositoryformatversion = 0</span><br><span class="line">filemode = true</span><br><span class="line">bare = false</span><br><span class="line">logallrefupdates = true</span><br><span class="line">ignorecase = true</span><br><span class="line">precomposeunicode = true</span><br></pre></td></tr></table></figure><ul><li>加了<code>--bare</code>创建的裸仓库:</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[core]</span><br><span class="line">repositoryformatversion = 0</span><br><span class="line">filemode = true</span><br><span class="line">bare = true</span><br><span class="line">ignorecase = true</span><br><span class="line">precomposeunicode = true</span><br></pre></td></tr></table></figure><p>可以看到最直观的差异在于<code>bare</code>配置项是否为<code>true</code>, 此外不加<code>--bare</code>创建的本地仓库配置中有一项<code>logallrefupdates = true</code>, 作用根据名字就可以看出来, 记录所有的<code>ref</code>(引用) 更新, 关于<code>ref</code>的部分之后有时间可以再写,这个配置可以理解为是 Git 的一道防线。</p><h4 id="功能差异"><a class="header-anchor" href="#功能差异">➡️</a>功能差异</h4><p>我们可以使用最简单的例子演示一下。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 直接创建本地仓库</span></span><br><span class="line">git ➤ git init repo</span><br><span class="line"><span class="meta">#</span><span class="bash"> 创建裸仓库</span></span><br><span class="line">git ➤ git init --bare repo.git</span><br><span class="line"><span class="meta">#</span><span class="bash"> 分别 <span class="built_in">clone</span> 两个仓库</span></span><br><span class="line">git ➤ git clone repo test1</span><br><span class="line">正克隆到 'test1'...</span><br><span class="line">warning: 您似乎克隆了一个空版本库。</span><br><span class="line">完成。</span><br><span class="line">git ➤ git clone repo.git test2</span><br><span class="line">正克隆到 'test2'...</span><br><span class="line">warning: 您似乎克隆了一个空版本库。</span><br><span class="line">完成。</span><br><span class="line">git ➤</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 进入 test1 仓库</span></span><br><span class="line">git ➤ cd test1</span><br><span class="line">test1 ➤ touch test git:master</span><br><span class="line">test1 ➤ git add . git:master*</span><br><span class="line">test1 ➤ git commit -m '测试提交' git:master*</span><br><span class="line">[master(根提交) 456cf23] 测试提交</span><br><span class="line"> 1 file changed, 0 insertions(+), 0 deletions(-)</span><br><span class="line"> create mode 100644 test</span><br><span class="line">test1 ➤ git push origin master git:master</span><br><span class="line">Counting objects: 3, done.</span><br><span class="line">Writing objects: 100% (3/3), 217 bytes | 0 bytes/s, done.</span><br><span class="line">Total 3 (delta 0), reused 0 (delta 0)</span><br><span class="line">remote: error: refusing to update checked out branch: refs/heads/master</span><br><span class="line">remote: error: By default, updating the current branch in a non-bare repository</span><br><span class="line">remote: error: is denied, because it will make the index and work tree inconsistent</span><br><span class="line">remote: error: with what you pushed, and will require 'git reset --hard' to match</span><br><span class="line">remote: error: the work tree to HEAD.</span><br><span class="line">remote: error:</span><br><span class="line">remote: error: You can set 'receive.denyCurrentBranch' configuration variable to</span><br><span class="line">remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into</span><br><span class="line">remote: error: its current branch; however, this is not recommended unless you</span><br><span class="line">remote: error: arranged to update its work tree to match what you pushed in some</span><br><span class="line">remote: error: other way.</span><br><span class="line">remote: error:</span><br><span class="line">remote: error: To squelch this message and still keep the default behaviour, set</span><br><span class="line">remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.</span><br><span class="line">To /home/git/repo</span><br><span class="line"> ! [remote rejected] master -> master (branch is currently checked out)</span><br><span class="line">error: 无法推送一些引用到 '/home/git/repo'</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 进入 test2 仓库重复执行</span></span><br><span class="line">test1 ➤ cd ../test2 git:master</span><br><span class="line">test2 ➤ touch test git:master</span><br><span class="line">test2 ➤ git add . git:master*</span><br><span class="line">test2 ➤ git commit -m '再次测试提交' git:master*</span><br><span class="line">[master(根提交) c56efe8] 再次测试提交</span><br><span class="line"> 1 file changed, 0 insertions(+), 0 deletions(-)</span><br><span class="line"> create mode 100644 test</span><br><span class="line">test2 ➤ git push origin master git:master</span><br><span class="line">Counting objects: 3, done.</span><br><span class="line">Writing objects: 100% (3/3), 223 bytes | 0 bytes/s, done.</span><br><span class="line">Total 3 (delta 0), reused 0 (delta 0)</span><br><span class="line">To /home/git/repo.git</span><br><span class="line"> * [new branch] master -> master</span><br><span class="line">test2 ➤</span><br></pre></td></tr></table></figure><p>从裸仓库中<code>clone</code>下来的本地仓库可以正常的<code>push</code>操作,这也正是裸仓库的存在意义</p><p>原文链接:<br><a href="https://moelove.info/2016/12/04/Git-%E6%9C%AC%E5%9C%B0%E4%BB%93%E5%BA%93%E5%92%8C%E8%A3%B8%E4%BB%93%E5%BA%93/" title="Git 本地仓库和裸仓库">Git 本地仓库和裸仓库</a></p>]]></content>
<summary type="html">
<h4 id="git-初始化"><a class="header-anchor" href="#git-初始化">➡️</a>git 初始化</h4>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git init #git目录初始化</span><br><span class="line">git init &lt;repo&gt; #本地初始化,并且建立一个名为repo的空仓库</span><br><span class="line">git init --bare #git裸仓库初始化</span><br><span class="line">git init --bare &lt;repo&gt; #指定某个目录成为中心仓库(裸仓库)</span><br></pre></td></tr></table></figure>
<p><code>git init</code>这个命令执行后会在本地生成一个 .git 的文件夹,用来追踪仓库的所有变更。<br>
<code>--bare</code>: 使用 --bare 参数初始化的仓库,我们一般称之为裸仓库, 因为这样创建的仓库并不包含 工作区 , 也就是说,我们并不能在这个目录下执行我们一般使用的 Git 命令。</p>
</summary>
</entry>
<entry>
<title>git 操作</title>
<link href="https://hexo.lilis.xin/posts/150d1834/"/>
<id>https://hexo.lilis.xin/posts/150d1834/</id>
<published>2019-09-11T07:36:04.000Z</published>
<updated>2019-09-19T09:52:52.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>收集一些不怎么常用的<code>git</code>操作,以做记录</p><a id="more"></a><h3 id="git-合并操作"><a class="header-anchor" href="#git-合并操作">➡️</a>git 合并操作</h3><p>通过<code>git log</code>查看提交记录及其commitId<br>再通过<code>git reset --soft commitId</code>来回退版本(–soft 和 --hard的区别就是 --soft是软回退,会将你这次commitId之后的提交全部回退到暂存区中,–hard会将你<br>这次commitId之后的提交全部清除掉)<br>此时你这次commitId之后的提交都会回到暂存区中<br>git commit -m 随便写注释</p><h3 id="git-忽略文件操作"><a class="header-anchor" href="#git-忽略文件操作">➡️</a>git 忽略文件操作</h3><p><code>git</code>忽略文件文件可以用<code>.gitignore</code>文件来实现,但如果一个文件已经被跟踪,再加入<code>.gitignore</code>文件就无效了。<br>这时可以<code>git rm --cached</code>,再更新<code>.gitignore</code>,忽略掉目标文件,最后再提交。<br>使用命令<code>git update-index --assume-unchanged 文件</code>来标记文件,使<code>git</code>停止关注这个需要被忽略的文件,这样也可以达成效果,但是这是一种不合理不规范的做法。<br>原因如下:<br>首先,<code>git update-index</code>的定义是:</p><div class="note primary"><p>Register file contents in the working tree to the index(把工作区下的文件内容注册到索引区)</p></div><p>也就是说<code>update-index</code>针对的是<code>git</code>数据库里被记录的文件,而不是那些需要忽略的文件。<br>接着看关于<code>--assume-unchanged</code>的描述:</p><div class="note primary"><p>When the “assume unchanged” bit is on, Git stops checking the working tree files for possible modifications, so you need to manually unset the bit to tell Git when you change the working tree file. This is sometimes helpful when working with a big project on a filesystem that has very slow lstat(2) system call (e.g. cifs).<br>应用了该标识之后,Git 停止查看工作区文件可能发生的改变,所以你必须 手动 重置该标识以便 Git 知道你想要恢复对文件改变的追踪。当你工作在一个大型项目中,这在文件系统的<code>lstat</code>系统调用非常迟钝的时候会很有用。</p></div><p>也就是说这个命令本身只是一种让<code>git</code>暂时忽略文件变动的操作。<br>主要是在修改一些大型文件时,防止<code>git</code>来回计算文件变化并更新工作区造成卡顿。<br><code>git update-index --assume-unchanged</code>的官方推荐用法是这样的:</p><ol><li>你正在修改一个巨大的文件,你先对其<code>git update-index --assume-unchanged</code>,这样<code>Git</code>暂时不会理睬你对文件做的修改;</li><li>当你的工作告一段落决定可以提交的时候,重置改标识:<code>git update-index --no-assume-unchanged</code>,于是<code>Git</code>只需要做一次更新,这是完全可以接受的了;</li><li>提交推送。</li></ol><p>另外,根据文档的进一步描述:</p><div class="note primary"><p>This option can be also used as a coarse file-level mechanism to ignore uncommitted changes in tracked files (akin to what .gitignore does for untracked files).</p></div><p>也就是说官方并不推荐这种做法,样的事情更应该用<code>.gitignore</code>文件来实现(针对未追踪的文件)。<br>随之而来的新问题是,为什么已经被跟踪的文件<code>.gitignore</code>会失去效果?<br>这是因为我们误解了<code>.gitignore</code>文件的用途,该文件只能作用于<code>Untracked Files</code>,也就是那些从来没有被<code>git</code>记录过的文件(自添加以后,从未 add 及 commit 过的文件)。<br>之所以你的规则不生效,是因为那些文件曾经被<code>git</code>记录过,因此<code>.gitignore</code>对它们完全无效。<br>因此,正确的做法应该先是<code>git rm --cached</code>,再更新<code>.gitignore</code>,忽略掉目标文件,最后再提交。</p><h3 id="git-撤回合并"><a class="header-anchor" href="#git-撤回合并">➡️</a>git 撤回合并</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git merge --abort</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>收集一些不怎么常用的<code>git</code>操作,以做记录</p>
</summary>
</entry>
<entry>
<title>基于Redis的GeoHash在PHP上的应用</title>
<link href="https://hexo.lilis.xin/posts/3dd74411/"/>
<id>https://hexo.lilis.xin/posts/3dd74411/</id>
<published>2018-11-29T07:26:08.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>GeoHash有着以下几个特点</p><ol><li>GeoHash用一个字符串表示经度和纬度两个坐标,便于加上索引.</li><li>GeoHash表示的并不是一个点,而是一个矩形区域.</li><li>编码的前缀可以表示更大的区域, 可以很方便的进行区域检索, 聚合等相关操作.</li></ol><p>综上所述, GeoHash比直接用经纬度的高效很多.</p><a id="more"></a><h3 id="GeoHash算法"><a class="header-anchor" href="#GeoHash算法">➡️</a>GeoHash算法</h3><p>编码</p><ul><li><p>GeoHash首先将精度范围设定为划分成两个区间(-180, 0), (0, 180), 如果经度坐标落到了前一个区间则标记为0, 反之则标记为1.</p></li><li><p>然后再将上一步获得到的区间划分成两个区间, 重复上一步.</p></li><li><p>重复前前两步直到得到自己所需要的精度</p></li><li><p>以此类推来得到纬度的HashBin (关于纬度的初始划分区间, 一般的共用算法里都是±90, 而redis里用的却是±85.05112878)<br>如 (23.17015353059966287, 113.46623629331588745) 通过区间划分可以得到:<br>(1101000010101111111001011110, 101000101101111011011100011)</p></li><li><p>接下来是对划分结果的合并, 按照<code>奇数位是纬度, 偶数位为经度</code>的原则来进行合并.<br>上面的例子合并可得:<br>1110011000000100110110011111111011111001011100101011110</p></li><li><p>之后再按照非标准的base32算法进行字符串的转化, 下面是对照表格</p></li></ul><table><thead><tr><th>十进制</th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th><th>9</th><th>10</th><th>11</th><th>12</th><th>13</th><th>14</th><th>15</th></tr></thead><tbody><tr><td>二进制</td><td>00000</td><td>00001</td><td>00010</td><td>00011</td><td>00100</td><td>00101</td><td>00110</td><td>00111</td><td>01000</td><td>01001</td><td>01010</td><td>01011</td><td>01100</td><td>01101</td><td>01110</td><td>01111</td></tr><tr><td>base32</td><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>b</td><td>c</td><td>d</td><td>e</td><td>f</td><td>g</td></tr><tr><td>十进制</td><td>16</td><td>17</td><td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td><td>25</td><td>26</td><td>27</td><td>28</td><td>29</td><td>30</td><td>31</td></tr><tr><td>二进制</td><td>10000</td><td>10001</td><td>10010</td><td>10011</td><td>10100</td><td>10101</td><td>10110</td><td>10111</td><td>11000</td><td>11001</td><td>11010</td><td>11011</td><td>11100</td><td>11101</td><td>11110</td><td>11111</td></tr><tr><td>base32</td><td>h</td><td>j</td><td>k</td><td>m</td><td>n</td><td>p</td><td>q</td><td>r</td><td>s</td><td>t</td><td>u</td><td>v</td><td>w</td><td>x</td><td>y</td><td>z</td></tr></tbody></table><p>最终(23.17015353059966287, 113.46623629331588745)被转化成’ws2emzrtfby’.</p><p>解码则和编码正好相反即可.</p><h3 id="PHP的实现"><a class="header-anchor" href="#PHP的实现">➡️</a>PHP的实现</h3><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Geohash</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="built_in">static</span> <span class="variable">$coding</span> = <span class="string">'0123456789bcdefghjkmnpqrstuvwxyz'</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="built_in">static</span> <span class="variable">$codingMap</span> = [</span><br><span class="line"> <span class="string">'0'</span> => <span class="string">'00000'</span>, <span class="string">'1'</span> => <span class="string">'00001'</span>, <span class="string">'2'</span> => <span class="string">'00010'</span>,</span><br><span class="line"> <span class="string">'3'</span> => <span class="string">'00011'</span>, <span class="string">'4'</span> => <span class="string">'00100'</span>, <span class="string">'5'</span> => <span class="string">'00101'</span>,</span><br><span class="line"> <span class="string">'6'</span> => <span class="string">'00110'</span>, <span class="string">'7'</span> => <span class="string">'00111'</span>, <span class="string">'8'</span> => <span class="string">'01000'</span>,</span><br><span class="line"> <span class="string">'9'</span> => <span class="string">'01001'</span>, <span class="string">'b'</span> => <span class="string">'01010'</span>, <span class="string">'c'</span> => <span class="string">'01011'</span>,</span><br><span class="line"> <span class="string">'d'</span> => <span class="string">'01100'</span>, <span class="string">'e'</span> => <span class="string">'01101'</span>, <span class="string">'f'</span> => <span class="string">'01110'</span>,</span><br><span class="line"> <span class="string">'g'</span> => <span class="string">'01111'</span>, <span class="string">'h'</span> => <span class="string">'10000'</span>, <span class="string">'j'</span> => <span class="string">'10001'</span>,</span><br><span class="line"> <span class="string">'k'</span> => <span class="string">'10010'</span>, <span class="string">'m'</span> => <span class="string">'10011'</span>, <span class="string">'n'</span> => <span class="string">'10100'</span>,</span><br><span class="line"> <span class="string">'p'</span> => <span class="string">'10101'</span>, <span class="string">'q'</span> => <span class="string">'10110'</span>, <span class="string">'r'</span> => <span class="string">'10111'</span>,</span><br><span class="line"> <span class="string">'s'</span> => <span class="string">'11000'</span>, <span class="string">'t'</span> => <span class="string">'11001'</span>, <span class="string">'u'</span> => <span class="string">'11010'</span>,</span><br><span class="line"> <span class="string">'v'</span> => <span class="string">'11011'</span>, <span class="string">'w'</span> => <span class="string">'11100'</span>, <span class="string">'x'</span> => <span class="string">'11101'</span>,</span><br><span class="line"> <span class="string">'y'</span> => <span class="string">'11110'</span>, <span class="string">'z'</span> => <span class="string">'11111'</span></span><br><span class="line"> ];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">decode</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$hash</span>, <span class="variable">$number</span> = <span class="literal">false</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$number</span>) {</span><br><span class="line"> <span class="variable">$binary</span> = base_convert(<span class="variable">$hash</span>, <span class="number">10</span>, <span class="number">2</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$binary</span> = <span class="string">''</span>;</span><br><span class="line"> <span class="variable">$hl</span> = strlen(<span class="variable">$hash</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$i</span>=<span class="number">0</span>; <span class="variable">$i</span><<span class="variable">$hl</span>; <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="variable">$binary</span> .= <span class="built_in">self</span>::<span class="variable">$codingMap</span>[substr(<span class="variable">$hash</span>,<span class="variable">$i</span>,<span class="number">1</span>)];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$bl</span> = strlen(<span class="variable">$binary</span>);</span><br><span class="line"> <span class="variable">$blat</span> = <span class="string">''</span>;</span><br><span class="line"> <span class="variable">$blong</span> = <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//取出经纬度</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$i</span>=<span class="number">0</span>; <span class="variable">$i</span><<span class="variable">$bl</span>; <span class="variable">$i</span>++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$i</span>%<span class="number">2</span>)</span><br><span class="line"> <span class="variable">$blat</span> = <span class="variable">$blat</span>.substr(<span class="variable">$binary</span>,<span class="variable">$i</span>,<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="variable">$blong</span> = <span class="variable">$blong</span>.substr(<span class="variable">$binary</span>,<span class="variable">$i</span>,<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//翻译经纬度</span></span><br><span class="line"> <span class="keyword">list</span>(</span><br><span class="line"> <span class="variable">$lat</span>,</span><br><span class="line"> <span class="variable">$latErr</span></span><br><span class="line"> ) = <span class="built_in">self</span>::binDecode(<span class="variable">$blat</span>,<span class="number">-85.05112878</span>,<span class="number">85.05112878</span>);</span><br><span class="line"> <span class="keyword">list</span>(</span><br><span class="line"> <span class="variable">$long</span>,</span><br><span class="line"> <span class="variable">$longErr</span></span><br><span class="line"> ) = <span class="built_in">self</span>::binDecode(<span class="variable">$blong</span>,<span class="number">-180</span>,<span class="number">180</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//精度处理</span></span><br><span class="line"> <span class="variable">$latPlaces</span> = max(<span class="number">1</span>, -round(log10(<span class="variable">$latErr</span>))) - <span class="number">1</span>;</span><br><span class="line"> <span class="variable">$longPlaces</span> = max(<span class="number">1</span>, -round(log10(<span class="variable">$longErr</span>))) - <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="variable">$lat</span> = round(<span class="variable">$lat</span>, <span class="variable">$latPlaces</span>);</span><br><span class="line"> <span class="variable">$long</span> = round(<span class="variable">$long</span>, <span class="variable">$longPlaces</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> [<span class="variable">$lat</span>, <span class="variable">$long</span>];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">hash2num</span>(<span class="params"><span class="keyword">string</span> <span class="variable">$hash</span>, <span class="variable">$bin</span> = <span class="literal">false</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="variable">$binary</span> = <span class="string">''</span>;</span><br><span class="line"> <span class="variable">$hl</span> = strlen(<span class="variable">$hash</span>);</span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$i</span>=<span class="number">0</span>; <span class="variable">$i</span><<span class="variable">$hl</span>; <span class="variable">$i</span>++)</span><br><span class="line"> {</span><br><span class="line"> <span class="variable">$binary</span> .= <span class="built_in">self</span>::<span class="variable">$codingMap</span>[substr(<span class="variable">$hash</span>,<span class="variable">$i</span>,<span class="number">1</span>)];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$bin</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$binary</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> base_convert(substr(<span class="variable">$binary</span>, <span class="number">0</span>, <span class="number">52</span>), <span class="number">2</span>, <span class="number">10</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 坐标转化</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> $lat</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> $long</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">encode</span>(<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="variable">$lat</span>, <span class="variable">$long</span>,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">bool</span> <span class="variable">$number</span> = <span class="literal">false</span></span></span></span><br><span class="line"><span class="function"><span class="params"> </span>) :<span class="title">string</span> </span>{</span><br><span class="line"> <span class="comment">//计算lat精度</span></span><br><span class="line"> <span class="variable">$latbits</span> = <span class="number">1</span>;</span><br><span class="line"> <span class="variable">$err</span> = <span class="number">45</span>;</span><br><span class="line"> <span class="variable">$plat</span> = <span class="built_in">self</span>::precision(<span class="variable">$lat</span>);</span><br><span class="line"> <span class="comment">//计算计算次数</span></span><br><span class="line"> <span class="keyword">while</span>(<span class="variable">$err</span> > <span class="variable">$plat</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="variable">$err</span> /= <span class="number">2</span>;</span><br><span class="line"> <span class="variable">$latbits</span> ++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$longbits</span> = <span class="number">1</span>;</span><br><span class="line"> <span class="variable">$err</span> = <span class="number">90</span>;</span><br><span class="line"> <span class="variable">$plong</span> = <span class="built_in">self</span>::precision(<span class="variable">$long</span>);</span><br><span class="line"> <span class="keyword">while</span>(<span class="variable">$err</span> > <span class="variable">$plong</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="variable">$err</span> /= <span class="number">2</span>;</span><br><span class="line"> <span class="variable">$longbits</span> ++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$bits</span> = max(<span class="variable">$latbits</span>, <span class="variable">$longbits</span>);</span><br><span class="line"></span><br><span class="line"> <span class="variable">$longbits</span> = <span class="variable">$bits</span>;</span><br><span class="line"> <span class="variable">$latbits</span> = <span class="variable">$bits</span>;</span><br><span class="line"> <span class="variable">$addlong</span> = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//为了可以进行合并填充数位 2^5 = 32</span></span><br><span class="line"> <span class="keyword">while</span> ((<span class="variable">$longbits</span>+<span class="variable">$latbits</span>)%<span class="number">5</span> != <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="variable">$longbits</span> += <span class="variable">$addlong</span>;</span><br><span class="line"> <span class="variable">$latbits</span> += !<span class="variable">$addlong</span>;</span><br><span class="line"> <span class="variable">$addlong</span> = !<span class="variable">$addlong</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="variable">$blat</span> = <span class="built_in">self</span>::binEncode(<span class="variable">$lat</span>,<span class="number">90</span>, <span class="number">90</span>, <span class="variable">$latbits</span>);</span><br><span class="line"> <span class="variable">$blong</span> = <span class="built_in">self</span>::binEncode(<span class="variable">$long</span>, <span class="number">-180</span>, <span class="number">180</span>, <span class="variable">$longbits</span>);</span><br><span class="line"></span><br><span class="line"> <span class="variable">$binary</span> = <span class="string">''</span>;</span><br><span class="line"> <span class="variable">$uselong</span> = <span class="number">1</span>;</span><br><span class="line"> <span class="variable">$strlen</span> = strlen(<span class="variable">$blat</span>) + strlen(<span class="variable">$blong</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//合并位数</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span><<span class="variable">$strlen</span>; <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$uselong</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="variable">$binary</span> .= substr(<span class="variable">$blong</span>,<span class="number">0</span>,<span class="number">1</span>);</span><br><span class="line"> <span class="variable">$blong</span> = substr(<span class="variable">$blong</span>,<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="variable">$binary</span> .= substr(<span class="variable">$blat</span>,<span class="number">0</span>,<span class="number">1</span>);</span><br><span class="line"> <span class="variable">$blat</span> = substr(<span class="variable">$blat</span>,<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable">$uselong</span> = !<span class="variable">$uselong</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$number</span>)</span><br><span class="line"> <span class="keyword">return</span> bindec(substr(<span class="variable">$binary</span>, <span class="number">0</span>, <span class="number">52</span>));</span><br><span class="line"></span><br><span class="line"> <span class="variable">$hash</span> = <span class="string">''</span>;</span><br><span class="line"> <span class="variable">$leng</span> = strlen(<span class="variable">$binary</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$i</span>=<span class="number">0</span>; <span class="variable">$i</span><<span class="variable">$leng</span>; <span class="variable">$i</span>+=<span class="number">5</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="variable">$n</span> = bindec(substr(<span class="variable">$binary</span>,<span class="variable">$i</span>,<span class="number">5</span>));</span><br><span class="line"> <span class="variable">$hash</span> = <span class="variable">$hash</span>. <span class="built_in">self</span>::<span class="variable">$coding</span>[<span class="variable">$n</span>];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="variable">$hash</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 计算精度</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> float $number</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> float|int</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">precision</span>(<span class="params"><span class="keyword">float</span> <span class="variable">$number</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="variable">$precision</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="variable">$pt</span> = strpos(<span class="variable">$number</span>,<span class="string">'.'</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$pt</span> !== <span class="literal">false</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="variable">$precision</span> = - (strlen(<span class="variable">$number</span>) - <span class="variable">$pt</span> - <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> pow(<span class="number">10</span>, <span class="variable">$precision</span>) / <span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">binEncode</span>(<span class="params"><span class="variable">$number</span>, <span class="variable">$min</span>, <span class="variable">$max</span>, <span class="variable">$bitcount</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$bitcount</span> == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"> <span class="variable">$mid</span> = bcdiv(bcadd(<span class="variable">$min</span>, <span class="variable">$max</span>, <span class="number">52</span>), <span class="number">2</span>, <span class="number">52</span>);</span><br><span class="line"> <span class="keyword">if</span> (bccomp(<span class="variable">$number</span>, <span class="variable">$mid</span>, <span class="number">52</span>) == <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'1'</span>. <span class="built_in">self</span>::binEncode(</span><br><span class="line"> <span class="variable">$number</span>, <span class="variable">$mid</span>,</span><br><span class="line"> <span class="variable">$max</span>,<span class="variable">$bitcount</span><span class="number">-1</span></span><br><span class="line"> );</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">'0'</span>. <span class="built_in">self</span>::binEncode(</span><br><span class="line"> <span class="variable">$number</span>, <span class="variable">$min</span>,</span><br><span class="line"> <span class="variable">$mid</span>,<span class="variable">$bitcount</span><span class="number">-1</span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="built_in">static</span> <span class="function"><span class="keyword">function</span> <span class="title">binDecode</span>(<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="variable">$binary</span>, <span class="variable">$min</span>,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="variable">$max</span></span></span></span><br><span class="line"><span class="function"><span class="params"> </span>) </span>{</span><br><span class="line"> <span class="variable">$binlen</span> = strlen(<span class="variable">$binary</span>);</span><br><span class="line"> <span class="variable">$err</span> = bcsub(<span class="variable">$max</span>, <span class="variable">$min</span>, <span class="number">52</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < <span class="variable">$binlen</span>; <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="variable">$bit</span> = substr(<span class="variable">$binary</span>,<span class="variable">$i</span>,<span class="number">1</span>);</span><br><span class="line"> <span class="variable">$mid</span> = bcdiv(bcadd(<span class="variable">$min</span>, <span class="variable">$max</span>, <span class="number">52</span>), <span class="number">2</span>, <span class="number">52</span>);</span><br><span class="line"> <span class="variable">$err</span> = bcdiv(<span class="variable">$err</span>, <span class="number">2</span>, <span class="number">52</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$bit</span> == <span class="number">1</span>) {</span><br><span class="line"> <span class="variable">$min</span> = <span class="variable">$mid</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$max</span> = <span class="variable">$mid</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> [<span class="variable">$mid</span>, <span class="variable">$err</span>];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Redis上的应用"><a class="header-anchor" href="#Redis上的应用">➡️</a>Redis上的应用</h3><p>Redis的GEO特性在<code>Redis 3.2</code>版本释出,这个功能可以将用户给定的地理位置信息储存起来,并对这些信息进行操作.</p><p><code>GEOADD</code></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GEOADD key longitude latitude name [longitude latitude name ...]</span><br></pre></td></tr></table></figure><p>GEOADD 命令每次可以添加一个或多个经纬度地理位置。 其中<code>key</code>为储存地理位置的集合, 而 <code>longitude</code> 、 <code>latitude</code> 和 <code>name</code> 则分别为地理位置的经度、纬度、名字.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> GEOADD geo_test 113.46623629331588745 23.17015353059966287 test_1 113.46620947122573853 23.17010790561879929 test_2</span><br></pre></td></tr></table></figure><p><code>GEOPOS</code><br><code>GEOPOS</code> 命令可以获取Geo的坐标</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GEOPOS key name [name ...]</span><br></pre></td></tr></table></figure><p>如:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> geopos geo_test test_2</span><br><span class="line">1) 1) "113.46620947122573853"</span><br><span class="line"> 2) "23.17010790561879929"</span><br></pre></td></tr></table></figure><p><code>GEODIST</code><br>计算两个坐标点之间的距离</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GEODIST key location-x location-y [unit]</span><br></pre></td></tr></table></figure><p>其中<code>unit</code>表示单位 默认为 <code>m</code></p><ul><li><code>m</code> 表示单位为米。</li><li><code>km</code> 表示单位为千米。</li><li><code>mi</code> 表示单位为英里。</li><li><code>ft</code> 表示单位为英尺。</li></ul><p><code>GEORADIUS</code> 和 <code>GEORADIUSBYMEMBER</code><br>这两个命令都是获取一定范围内的坐标</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GEORADIUS key longitude latitude radius m|km|ft|mi[WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]</span><br><span class="line">GEORADIUSBYMEMBER key location radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]</span><br></pre></td></tr></table></figure><ul><li><code>WITHCOORD</code> 在返回匹配的位置时会将位置的经纬度一并返回.</li><li><code>WITHDIST</code> 指定中心返回项目的距离, 距离以与指定为命令的radius参数的单位相同的单位返回.</li><li><code>WITHHASH</code> 还以52位无符号整数的形式返回项的原始geohash编码的有序集分数</li><li><code>ASC|DESC</code> <code>ASC</code> 可以让查找结果根据距离从近到远排序, 而 <code>DESC</code> 则可以让查找结果根据从远到近排序</li><li><code>COUNT</code> 指定要返回的结果数量</li><li><code>STORE key</code> 结果存到新的有序集合中, 以<code>GeoHash</code>值做<code>score</code>, 该选项与<code>WITH[DIST|COORD|HASH]</code>选项冲突</li><li><code>STOREDIST key</code> 结果存到新的有序集合中, 以与指定位置的距离作<code>score</code>, 该选项与<code>WITH[DIST|COORD|HASH]</code>选项冲突</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> georadius key 113.46620947122573853 23.17010790561879929 100 km WITHCOORD WITHDIST</span><br><span class="line">1) 1) "test_2"</span><br><span class="line"> 2) "0.0000"</span><br><span class="line"> 3) 1) "113.46620947122573853"</span><br><span class="line"> 2) "23.17010790561879929"</span><br><span class="line">127.0.0.1:6379></span><br></pre></td></tr></table></figure><p><code>GEOHASH</code><br>将redis里的<code>Geo</code>转化为标准的<code>GeoHash</code>输出<br>注意:这里输出的是标准的<code>GeoHash</code>, 不是redis里面存储的<code>HashInt</code>转化出来的</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GEOHASH key member [member ...]</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> geohash geo_test test_1 test_2</span><br><span class="line">1) "7pkg3sdkv40"</span><br><span class="line">2) "ws0evczxdm0"</span><br></pre></td></tr></table></figure><h4 id="存储原理"><a class="header-anchor" href="#存储原理">➡️</a>存储原理</h4><p><code>Redis</code>里的<code>Geo</code>坐标在实际存储时是将<code>gps</code>坐标分别按照(-180, 180)和(-85.05112878, 85.05112878)来划分计算成<code>HashInt</code>作为<code>zset集合</code>进行存储的.<br>所以<code>Redis</code>的<code>Geo</code>操作中并没有删除命令, 可以直接使用<code>zrem</code>命令去删除<code>Geo</code>坐标.</p>]]></content>
<summary type="html">
<p>GeoHash有着以下几个特点</p>
<ol>
<li>GeoHash用一个字符串表示经度和纬度两个坐标,便于加上索引.</li>
<li>GeoHash表示的并不是一个点,而是一个矩形区域.</li>
<li>编码的前缀可以表示更大的区域, 可以很方便的进行区域检索, 聚合等相关操作.</li>
</ol>
<p>综上所述, GeoHash比直接用经纬度的高效很多.</p>
</summary>
<category term="PHP" scheme="https://hexo.lilis.xin/tags/PHP/"/>
<category term="redis" scheme="https://hexo.lilis.xin/tags/redis/"/>
<category term="GeoHash" scheme="https://hexo.lilis.xin/tags/GeoHash/"/>
<category term="GPS" scheme="https://hexo.lilis.xin/tags/GPS/"/>
</entry>
<entry>
<title>nginx服务脚本</title>
<link href="https://hexo.lilis.xin/posts/5bc4c6e7/"/>
<id>https://hexo.lilis.xin/posts/5bc4c6e7/</id>
<published>2018-11-14T04:49:30.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>nginx服务脚本</p><a id="more"></a><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">!/bin/sh</span></span><br><span class="line"><span class="meta">#</span></span><br><span class="line"><span class="bash"><span class="comment"># nginx - this script starts and stops the nginx daemin</span></span></span><br><span class="line"><span class="meta">#</span></span><br><span class="line"><span class="bash"><span class="comment"># chkconfig: - 85 15</span></span> </span><br><span class="line"><span class="meta">#</span><span class="bash"> description: Nginx is an HTTP(S) server, HTTP(S) reverse \</span></span><br><span class="line"><span class="bash"><span class="comment"># proxy and IMAP/POP3 proxy server</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> processname: nginx</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> config: /usr/<span class="built_in">local</span>/nginx/conf/nginx.conf</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> pidfile: /usr/<span class="built_in">local</span>/nginx/logs/nginx.pid</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> Source <span class="keyword">function</span> library.</span></span><br><span class="line">. /etc/rc.d/init.d/functions</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> Source networking configuration.</span></span><br><span class="line">. /etc/sysconfig/network</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> Check that networking is up.</span></span><br><span class="line">[ "$NETWORKING" = "no" ] && exit 0</span><br><span class="line"></span><br><span class="line">nginx="/usr/local/sbin/nginx"</span><br><span class="line">prog=$(basename $nginx)</span><br><span class="line"></span><br><span class="line">NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"</span><br><span class="line"></span><br><span class="line">lockfile=/var/lock/subsys/nginx</span><br><span class="line"></span><br><span class="line">start() {</span><br><span class="line"> [ -x $nginx ] || exit 5</span><br><span class="line"> [ -f $NGINX_CONF_FILE ] || exit 6</span><br><span class="line"> echo -n $"Starting $prog: "</span><br><span class="line"> daemon $nginx -c $NGINX_CONF_FILE</span><br><span class="line"> retval=$?</span><br><span class="line"> echo</span><br><span class="line"> [ $retval -eq 0 ] && touch $lockfile</span><br><span class="line"> return $retval</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">stop() {</span><br><span class="line"> echo -n $"Stopping $prog: "</span><br><span class="line"> killproc $prog -QUIT</span><br><span class="line"> retval=$?</span><br><span class="line"> echo</span><br><span class="line"> [ $retval -eq 0 ] && rm -f $lockfile</span><br><span class="line"> return $retval</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">restart() {</span><br><span class="line"> configtest || return $?</span><br><span class="line"> stop</span><br><span class="line"> start</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">reload() {</span><br><span class="line"> configtest || return $?</span><br><span class="line"> echo -n $"Reloading $prog: "</span><br><span class="line"> killproc $nginx -HUP</span><br><span class="line"> RETVAL=$?</span><br><span class="line"> echo</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">force_reload() {</span><br><span class="line"> restart</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">configtest() {</span><br><span class="line"><span class="meta"> $</span><span class="bash">nginx -t -c <span class="variable">$NGINX_CONF_FILE</span></span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">rh_status() {</span><br><span class="line"> status $prog</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">rh_status_q() {</span><br><span class="line"> rh_status >/dev/null 2>&1</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">case "$1" in</span><br><span class="line"> start)</span><br><span class="line"> rh_status_q && exit 0</span><br><span class="line"> $1</span><br><span class="line"> ;;</span><br><span class="line"> stop)</span><br><span class="line"> rh_status_q || exit 0</span><br><span class="line"> $1</span><br><span class="line"> ;;</span><br><span class="line"> restart|configtest)</span><br><span class="line"> $1</span><br><span class="line"> ;;</span><br><span class="line"> reload)</span><br><span class="line"> rh_status_q || exit 7</span><br><span class="line"> $1</span><br><span class="line"> ;;</span><br><span class="line"> force-reload)</span><br><span class="line"> force_reload</span><br><span class="line"> ;;</span><br><span class="line"> status)</span><br><span class="line"> rh_status</span><br><span class="line"> ;;</span><br><span class="line"> condrestart|try-restart)</span><br><span class="line"> rh_status_q || exit 0</span><br><span class="line"> ;;</span><br><span class="line"> *)</span><br><span class="line"> echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"</span><br><span class="line"> exit 2</span><br><span class="line">esac</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>nginx服务脚本</p>
</summary>
<category term="nginx" scheme="https://hexo.lilis.xin/tags/nginx/"/>
<category term="server" scheme="https://hexo.lilis.xin/tags/server/"/>
</entry>
<entry>
<title>PHP动态gif验证码</title>
<link href="https://hexo.lilis.xin/posts/491b8778/"/>
<id>https://hexo.lilis.xin/posts/491b8778/</id>
<published>2018-11-08T04:02:23.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>最近感觉自己的项目上的验证码太low了,决定换一个有意思的动态gif验证码</p><a id="more"></a><p>效果<br><img src="https://blog.lilis.xin/wp-admin/Captcha.php" alt="Captcha" title="Captcha"><br>废话不多说,直接上源码</p><h4 id="源码"><a class="header-anchor" href="#源码">➡️</a>源码</h4><p>主函数:<br><a href="https://blog.lilis.xin/wp-admin/fonts/comic.ttf" title="comic.ttf">comic.ttf</a></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">ImageCode</span>(<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="variable">$string</span>=<span class="string">''</span>, <span class="variable">$frames</span> = <span class="number">60</span>,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="variable">$time</span> = <span class="number">1</span>,<span class="variable">$width</span>=<span class="number">75</span>,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="variable">$height</span>=<span class="number">25</span>, <span class="variable">$font</span> = <span class="number">6</span>,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="variable">$loops</span> = <span class="number">0</span></span></span></span><br><span class="line"><span class="function"><span class="params"> </span>) </span>{</span><br><span class="line"> <span class="variable">$authstr</span> = <span class="variable">$string</span>?:((time()%<span class="number">2</span>==<span class="number">0</span>)?mt_rand(<span class="number">1000</span>,<span class="number">9999</span>):mt_rand(<span class="number">10000</span>,<span class="number">99999</span>));</span><br><span class="line"> <span class="variable">$authlen</span> = strlen(<span class="variable">$authstr</span>);</span><br><span class="line"> <span class="variable">$board_width</span>=<span class="variable">$width</span>;</span><br><span class="line"> <span class="variable">$board_height</span>=<span class="variable">$height</span>;</span><br><span class="line"> <span class="variable">$delay</span> = <span class="variable">$time</span>*<span class="number">100</span>/<span class="variable">$frames</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 生成一个n帧的GIF动画</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$i</span>=<span class="number">0</span>;<span class="variable">$i</span><<span class="variable">$frames</span>;<span class="variable">$i</span>++){</span><br><span class="line"> ob_start();</span><br><span class="line"> <span class="variable">$image</span>=imagecreate(<span class="variable">$board_width</span>,<span class="variable">$board_height</span>);</span><br><span class="line"> imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设定文字颜色数组</span></span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">15</span>,<span class="number">73</span>,<span class="number">210</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">64</span>,<span class="number">0</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">64</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">128</span>,<span class="number">128</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">27</span>,<span class="number">52</span>,<span class="number">47</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">51</span>,<span class="number">0</span>,<span class="number">102</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">145</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">113</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">51</span>,<span class="number">51</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">158</span>,<span class="number">180</span>,<span class="number">35</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">59</span>,<span class="number">59</span>,<span class="number">59</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">1</span>,<span class="number">128</span>,<span class="number">180</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">153</span>,<span class="number">51</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">60</span>,<span class="number">131</span>,<span class="number">1</span>);</span><br><span class="line"> <span class="variable">$colorList</span>[]=imagecolorallocate(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line"> <span class="variable">$gray</span>=imagecolorallocate(<span class="variable">$image</span>,<span class="number">245</span>,<span class="number">245</span>,<span class="number">245</span>);</span><br><span class="line"> imagefill(<span class="variable">$image</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="variable">$gray</span>);</span><br><span class="line"> <span class="variable">$space</span>=<span class="variable">$font</span>*<span class="number">0.65</span>;<span class="comment">// 字符间距</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$k</span>=<span class="number">0</span>;<span class="variable">$k</span><<span class="variable">$authlen</span>;<span class="variable">$k</span>++){</span><br><span class="line"> <span class="variable">$colorRandom</span>=mt_rand(<span class="number">0</span>,sizeof(<span class="variable">$colorList</span>)<span class="number">-1</span>);</span><br><span class="line"> <span class="variable">$float_top</span>=rand(<span class="number">0</span>,<span class="number">4</span>);</span><br><span class="line"> <span class="variable">$float_left</span>=rand(<span class="number">1</span>,<span class="number">4</span>);</span><br><span class="line"> imagettftext(</span><br><span class="line"> <span class="variable">$image</span>, <span class="variable">$font</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="variable">$space</span>*<span class="variable">$k</span>+<span class="variable">$float_left</span>, <span class="variable">$font</span>+<span class="variable">$float_top</span>,</span><br><span class="line"> <span class="variable">$colorList</span>[<span class="variable">$colorRandom</span>],</span><br><span class="line"> <span class="string">'./fonts/comic.ttf'</span>,</span><br><span class="line"> substr(<span class="variable">$authstr</span>,<span class="variable">$k</span>,<span class="number">1</span>)</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$k</span>=<span class="number">0</span>;<span class="variable">$k</span><<span class="number">20</span>;<span class="variable">$k</span>++){</span><br><span class="line"> <span class="variable">$colorRandom</span>=mt_rand(<span class="number">0</span>,sizeof(<span class="variable">$colorList</span>)<span class="number">-1</span>);</span><br><span class="line"> imagesetpixel(<span class="variable">$image</span>,rand()%<span class="number">70</span>,rand()%<span class="number">15</span>,<span class="variable">$colorList</span>[<span class="variable">$colorRandom</span>]);</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 添加干扰线</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="variable">$k</span>=<span class="number">0</span>;<span class="variable">$k</span><<span class="number">3</span>;<span class="variable">$k</span>++){</span><br><span class="line"> <span class="variable">$colorRandom</span>=mt_rand(<span class="number">0</span>,sizeof(<span class="variable">$colorList</span>)<span class="number">-1</span>);</span><br><span class="line"> <span class="variable">$toDrawLine</span>=<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span>(<span class="variable">$toDrawLine</span>){</span><br><span class="line"> imageline(<span class="variable">$image</span>,mt_rand(<span class="number">0</span>,<span class="variable">$board_width</span>),mt_rand(<span class="number">0</span>,<span class="variable">$board_height</span>),mt_rand(<span class="number">0</span>,<span class="variable">$board_width</span>),mt_rand(<span class="number">0</span>,<span class="variable">$board_height</span>),<span class="variable">$colorList</span>[<span class="variable">$colorRandom</span>]);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="variable">$w</span>=mt_rand(<span class="number">0</span>,<span class="variable">$board_width</span>);</span><br><span class="line"> <span class="variable">$h</span>=mt_rand(<span class="number">0</span>,<span class="variable">$board_width</span>);</span><br><span class="line"> imagearc(<span class="variable">$image</span>,<span class="variable">$board_width</span>-floor(<span class="variable">$w</span> / <span class="number">2</span>),floor(<span class="variable">$h</span> / <span class="number">2</span>),<span class="variable">$w</span>,<span class="variable">$h</span>, rand(<span class="number">90</span>,<span class="number">180</span>),rand(<span class="number">180</span>,<span class="number">270</span>),<span class="variable">$colorList</span>[<span class="variable">$colorRandom</span>]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> imagegif(<span class="variable">$image</span>);</span><br><span class="line"> imagedestroy(<span class="variable">$image</span>);</span><br><span class="line"> <span class="variable">$imagedata</span>[]=ob_get_contents();</span><br><span class="line"> <span class="variable">$delays</span>[] = <span class="variable">$delay</span>;</span><br><span class="line"> ob_clean();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> AnimatedGif(<span class="variable">$imagedata</span>, <span class="variable">$delays</span>, <span class="variable">$loops</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>AnimatedGif:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *AnimatedGif类</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AnimatedGif</span> </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The built gif image</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@var</span> resource</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$image</span> = <span class="string">''</span>;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The array of images to stack</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@var</span> array</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$buffer</span> = <span class="keyword">Array</span>();</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * How many times to loop? 0 = infinite</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@var</span> int</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$number_of_loops</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@var</span> int</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$DIS</span> = <span class="number">2</span>;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Which colour is transparent</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@var</span> int</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$transparent_colour</span> = <span class="number">-1</span>;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Is this the first frame</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@var</span> int</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$first_frame</span> = <span class="literal">TRUE</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Encode an animated gif</span></span><br><span class="line"><span class="comment"> * AnimatedGif constructor.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> array $source_images</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> array $image_delays</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> $number_of_loops</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">array</span> <span class="variable">$source_images</span>,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">array</span> <span class="variable">$image_delays</span>,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="variable">$number_of_loops</span></span></span></span><br><span class="line"><span class="function"><span class="params"> </span>) </span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * I have no idea what these even do, they appear to do nothing to the image so far</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="variable">$transparent_colour_red</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="variable">$transparent_colour_green</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="variable">$transparent_colour_blue</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">$this</span>->number_of_loops = ( <span class="variable">$number_of_loops</span> > <span class="number">-1</span> ) ? <span class="variable">$number_of_loops</span> : <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">$this</span>->set_transparent_colour(<span class="variable">$transparent_colour_red</span>, <span class="variable">$transparent_colour_green</span>, <span class="variable">$transparent_colour_blue</span>);</span><br><span class="line"> <span class="keyword">$this</span>->buffer_images(<span class="variable">$source_images</span>);</span><br><span class="line"> <span class="keyword">$this</span>->addHeader();</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < count(<span class="keyword">$this</span>->buffer); <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="keyword">$this</span>->addFrame(<span class="variable">$i</span>, <span class="variable">$image_delays</span> [<span class="variable">$i</span>]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Set the transparent colour</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> int $red</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> int $green</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> int $blue</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">set_transparent_colour</span>(<span class="params"><span class="variable">$red</span>, <span class="variable">$green</span>, <span class="variable">$blue</span></span>)</span>{</span><br><span class="line"> <span class="keyword">$this</span>->transparent_colour = ( <span class="variable">$red</span> > <span class="number">-1</span> && <span class="variable">$green</span> > <span class="number">-1</span> && <span class="variable">$blue</span> > <span class="number">-1</span> ) ?</span><br><span class="line"> ( <span class="variable">$red</span> | ( <span class="variable">$green</span> << <span class="number">8</span> ) | ( <span class="variable">$blue</span> << <span class="number">16</span> ) ) : <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Buffer the images and check to make sure they are vaild</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> $source_images</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">buffer_images</span>(<span class="params"><span class="variable">$source_images</span></span>) </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < count(<span class="variable">$source_images</span>); <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="keyword">$this</span>->buffer [] = <span class="variable">$source_images</span> [<span class="variable">$i</span>];</span><br><span class="line"> <span class="keyword">if</span> (substr(<span class="keyword">$this</span>->buffer [<span class="variable">$i</span>], <span class="number">0</span>, <span class="number">6</span>) != <span class="string">"GIF87a"</span> && substr(<span class="keyword">$this</span>->buffer [<span class="variable">$i</span>], <span class="number">0</span>, <span class="number">6</span>) != <span class="string">"GIF89a"</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">'Image at position '</span> . <span class="variable">$i</span>. <span class="string">' is not a gif'</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$j</span> = ( <span class="number">13</span> + <span class="number">3</span> * ( <span class="number">2</span> << ( ord(<span class="keyword">$this</span>->buffer [<span class="variable">$i</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> ) ) ), <span class="variable">$k</span> = <span class="literal">TRUE</span>; <span class="variable">$k</span>; <span class="variable">$j</span>++) {</span><br><span class="line"> <span class="keyword">switch</span> (<span class="keyword">$this</span>->buffer [<span class="variable">$i</span>] { <span class="variable">$j</span> }) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"!"</span>:</span><br><span class="line"> <span class="keyword">if</span> (( substr(<span class="keyword">$this</span>->buffer [<span class="variable">$i</span>], ( <span class="variable">$j</span> + <span class="number">3</span>), <span class="number">8</span>) ) == <span class="string">"NETSCAPE"</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Exception</span>(<span class="string">'You cannot make an animation from an animated gif.'</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">";"</span>:</span><br><span class="line"> <span class="variable">$k</span> = <span class="literal">FALSE</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Add the gif header to the image</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">addHeader</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="variable">$cmap</span> = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">$this</span>->image = <span class="string">'GIF89a'</span>;</span><br><span class="line"> <span class="keyword">if</span> (ord(<span class="keyword">$this</span>->buffer [<span class="number">0</span>] { <span class="number">10</span> }) & <span class="number">0x80</span>) {</span><br><span class="line"> <span class="variable">$cmap</span> = <span class="number">3</span> * ( <span class="number">2</span> << ( ord(<span class="keyword">$this</span>->buffer [<span class="number">0</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> ) );</span><br><span class="line"> <span class="keyword">$this</span>->image .= substr(<span class="keyword">$this</span>->buffer [<span class="number">0</span>], <span class="number">6</span>, <span class="number">7</span>);</span><br><span class="line"> <span class="keyword">$this</span>->image .= substr(<span class="keyword">$this</span>->buffer [<span class="number">0</span>], <span class="number">13</span>, <span class="variable">$cmap</span>);</span><br><span class="line"> <span class="keyword">$this</span>->image .= <span class="string">"!\377\13NETSCAPE2.0\3\1"</span> . <span class="keyword">$this</span>->word(<span class="keyword">$this</span>->number_of_loops) . <span class="string">"\0"</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Add a frame to the animation</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> int $frame The frame to be added</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> int $delay The delay associated with the frame</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">addFrame</span>(<span class="params"><span class="variable">$frame</span>, <span class="variable">$delay</span></span>) </span>{</span><br><span class="line"> <span class="variable">$Locals_str</span> = <span class="number">13</span> + <span class="number">3</span> * ( <span class="number">2</span> << ( ord(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> ) );</span><br><span class="line"> <span class="variable">$Locals_end</span> = strlen(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>]) - <span class="variable">$Locals_str</span> - <span class="number">1</span>;</span><br><span class="line"> <span class="variable">$Locals_tmp</span> = substr(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>], <span class="variable">$Locals_str</span>, <span class="variable">$Locals_end</span>);</span><br><span class="line"> <span class="variable">$Global_len</span> = <span class="number">2</span> << ( ord(<span class="keyword">$this</span>->buffer [<span class="number">0</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> );</span><br><span class="line"> <span class="variable">$Locals_len</span> = <span class="number">2</span> << ( ord(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> );</span><br><span class="line"> <span class="variable">$Global_rgb</span> = substr(<span class="keyword">$this</span>->buffer [<span class="number">0</span>], <span class="number">13</span>, <span class="number">3</span> * ( <span class="number">2</span> << ( ord(<span class="keyword">$this</span>->buffer [<span class="number">0</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> ) ));</span><br><span class="line"> <span class="variable">$Locals_rgb</span> = substr(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>], <span class="number">13</span>, <span class="number">3</span> * ( <span class="number">2</span> << ( ord(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> ) ));</span><br><span class="line"> <span class="variable">$Locals_ext</span> = <span class="string">"!\xF9\x04"</span> . chr(( <span class="keyword">$this</span>->DIS << <span class="number">2</span> ) + <span class="number">0</span>) .</span><br><span class="line"> chr(( <span class="variable">$delay</span> >> <span class="number">0</span> ) & <span class="number">0xFF</span>) . chr(( <span class="variable">$delay</span> >> <span class="number">8</span> ) & <span class="number">0xFF</span>) . <span class="string">"\x0\x0"</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->transparent_colour > <span class="number">-1</span> && ord(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>] { <span class="number">10</span> }) & <span class="number">0x80</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$j</span> = <span class="number">0</span>; <span class="variable">$j</span> < ( <span class="number">2</span> << ( ord(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> ) ); <span class="variable">$j</span>++) {</span><br><span class="line"> <span class="keyword">if</span> (</span><br><span class="line"> ord(<span class="variable">$Locals_rgb</span> { <span class="number">3</span> * <span class="variable">$j</span> + <span class="number">0</span> }) == ( ( <span class="keyword">$this</span>->transparent_colour >> <span class="number">16</span> ) & <span class="number">0xFF</span> ) &&</span><br><span class="line"> ord(<span class="variable">$Locals_rgb</span> { <span class="number">3</span> * <span class="variable">$j</span> + <span class="number">1</span> }) == ( ( <span class="keyword">$this</span>->transparent_colour >> <span class="number">8</span> ) & <span class="number">0xFF</span> ) &&</span><br><span class="line"> ord(<span class="variable">$Locals_rgb</span> { <span class="number">3</span> * <span class="variable">$j</span> + <span class="number">2</span> }) == ( ( <span class="keyword">$this</span>->transparent_colour >> <span class="number">0</span> ) & <span class="number">0xFF</span> )</span><br><span class="line"> ) {</span><br><span class="line"> <span class="variable">$Locals_ext</span> = <span class="string">"!\xF9\x04"</span> . chr(( <span class="keyword">$this</span>->DIS << <span class="number">2</span> ) + <span class="number">1</span>) .</span><br><span class="line"> chr(( <span class="variable">$delay</span> >> <span class="number">0</span> ) & <span class="number">0xFF</span>) . chr(( <span class="variable">$delay</span> >> <span class="number">8</span> ) & <span class="number">0xFF</span>) . chr(<span class="variable">$j</span>) . <span class="string">"\x0"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">switch</span> (<span class="variable">$Locals_tmp</span> { <span class="number">0</span> }) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"!"</span>:</span><br><span class="line"> <span class="variable">$Locals_img</span> = substr(<span class="variable">$Locals_tmp</span>, <span class="number">8</span>, <span class="number">10</span>);</span><br><span class="line"> <span class="variable">$Locals_tmp</span> = substr(<span class="variable">$Locals_tmp</span>, <span class="number">18</span>, strlen(<span class="variable">$Locals_tmp</span>) - <span class="number">18</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">","</span>:</span><br><span class="line"> <span class="variable">$Locals_img</span> = substr(<span class="variable">$Locals_tmp</span>, <span class="number">0</span>, <span class="number">10</span>);</span><br><span class="line"> <span class="variable">$Locals_tmp</span> = substr(<span class="variable">$Locals_tmp</span>, <span class="number">10</span>, strlen(<span class="variable">$Locals_tmp</span>) - <span class="number">10</span>);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (ord(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>] { <span class="number">10</span> }) & <span class="number">0x80</span> && <span class="keyword">$this</span>->first_frame === <span class="literal">FALSE</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable">$Global_len</span> == <span class="variable">$Locals_len</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">$this</span>->blockCompare(<span class="variable">$Global_rgb</span>, <span class="variable">$Locals_rgb</span>, <span class="variable">$Global_len</span>)) {</span><br><span class="line"> <span class="keyword">$this</span>->image .= ( <span class="variable">$Locals_ext</span> . <span class="variable">$Locals_img</span> . <span class="variable">$Locals_tmp</span> );</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$byte</span> = ord(<span class="variable">$Locals_img</span> { <span class="number">9</span> });</span><br><span class="line"> <span class="variable">$byte</span> |= <span class="number">0x80</span>;</span><br><span class="line"> <span class="variable">$byte</span> &= <span class="number">0xF8</span>;</span><br><span class="line"> <span class="variable">$byte</span> |= ( ord(<span class="keyword">$this</span>->buffer [<span class="number">0</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> );</span><br><span class="line"> <span class="variable">$Locals_img</span> { <span class="number">9</span> } = chr(<span class="variable">$byte</span>);</span><br><span class="line"> <span class="keyword">$this</span>->image .= ( <span class="variable">$Locals_ext</span> . <span class="variable">$Locals_img</span> . <span class="variable">$Locals_rgb</span> . <span class="variable">$Locals_tmp</span> );</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable">$byte</span> = ord(<span class="variable">$Locals_img</span> { <span class="number">9</span> });</span><br><span class="line"> <span class="variable">$byte</span> |= <span class="number">0x80</span>;</span><br><span class="line"> <span class="variable">$byte</span> &= <span class="number">0xF8</span>;</span><br><span class="line"> <span class="variable">$byte</span> |= ( ord(<span class="keyword">$this</span>->buffer [<span class="variable">$frame</span>] { <span class="number">10</span> }) & <span class="number">0x07</span> );</span><br><span class="line"> <span class="variable">$Locals_img</span> { <span class="number">9</span> } = chr(<span class="variable">$byte</span>);</span><br><span class="line"> <span class="keyword">$this</span>->image .= ( <span class="variable">$Locals_ext</span> . <span class="variable">$Locals_img</span> . <span class="variable">$Locals_rgb</span> . <span class="variable">$Locals_tmp</span> );</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">$this</span>->image .= ( <span class="variable">$Locals_ext</span> . <span class="variable">$Locals_img</span> . <span class="variable">$Locals_tmp</span> );</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">$this</span>->first_frame = <span class="literal">FALSE</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Add the gif footer</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">addFooter</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">$this</span>->image .= <span class="string">";"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Compare gif blocks? What is a block?</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> $GlobalBlock</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> $LocalBlock</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> $Len</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> int</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">blockCompare</span>(<span class="params"><span class="variable">$GlobalBlock</span>, <span class="variable">$LocalBlock</span>, <span class="variable">$Len</span></span>) </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < <span class="variable">$Len</span>; <span class="variable">$i</span>++) {</span><br><span class="line"> <span class="keyword">if</span> (</span><br><span class="line"> <span class="variable">$GlobalBlock</span> { <span class="number">3</span> * <span class="variable">$i</span> + <span class="number">0</span> } != <span class="variable">$LocalBlock</span> { <span class="number">3</span> * <span class="variable">$i</span> + <span class="number">0</span> } ||</span><br><span class="line"> <span class="variable">$GlobalBlock</span> { <span class="number">3</span> * <span class="variable">$i</span> + <span class="number">1</span> } != <span class="variable">$LocalBlock</span> { <span class="number">3</span> * <span class="variable">$i</span> + <span class="number">1</span> } ||</span><br><span class="line"> <span class="variable">$GlobalBlock</span> { <span class="number">3</span> * <span class="variable">$i</span> + <span class="number">2</span> } != <span class="variable">$LocalBlock</span> { <span class="number">3</span> * <span class="variable">$i</span> + <span class="number">2</span> }</span><br><span class="line"> ) {</span><br><span class="line"> <span class="keyword">return</span> ( <span class="number">0</span> );</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ( <span class="number">1</span> );</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * No clue</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> int $int</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> string the char you meant?</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="function"><span class="keyword">function</span> <span class="title">word</span>(<span class="params"><span class="variable">$int</span></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> ( chr(<span class="variable">$int</span> & <span class="number">0xFF</span>) . chr(( <span class="variable">$int</span> >> <span class="number">8</span> ) & <span class="number">0xFF</span>) );</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Return the animated gif</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> resource</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">getAnimation</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">$this</span>->image;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Return the animated gif</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@echo</span> image</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">display</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="comment">//late footer add</span></span><br><span class="line"> <span class="keyword">$this</span>->addFooter();</span><br><span class="line"> header(<span class="string">'Content-type:image/gif'</span>);</span><br><span class="line"> <span class="keyword">echo</span> <span class="keyword">$this</span>->image;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>使用示例代码:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$str</span> = <span class="string">'abcdefghijkmnpqrstuvwxy3456789'</span>;</span><br><span class="line"><span class="variable">$len</span> = strlen(<span class="variable">$str</span>) - <span class="number">1</span>;</span><br><span class="line"><span class="variable">$text</span> = <span class="string">''</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="variable">$i</span> = <span class="number">0</span>; <span class="variable">$i</span> < <span class="number">6</span>; <span class="variable">$i</span>++) {</span><br><span class="line"><span class="variable">$text</span> .= <span class="variable">$str</span>[rand(<span class="number">0</span>, <span class="variable">$len</span>)];</span><br><span class="line">}</span><br><span class="line"><span class="variable">$gif</span> = ImageCode(</span><br><span class="line"><span class="variable">$text</span>, <span class="number">8</span>, <span class="number">1</span>,</span><br><span class="line"><span class="number">100</span>, <span class="number">35</span>,</span><br><span class="line"><span class="number">23</span></span><br><span class="line">);</span><br><span class="line"><span class="variable">$gif</span>->display();</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>最近感觉自己的项目上的验证码太low了,决定换一个有意思的动态gif验证码</p>
</summary>
<category term="PHP" scheme="https://hexo.lilis.xin/tags/PHP/"/>
<category term="代码" scheme="https://hexo.lilis.xin/tags/%E4%BB%A3%E7%A0%81/"/>
<category term="captcha" scheme="https://hexo.lilis.xin/tags/captcha/"/>
<category term="gif" scheme="https://hexo.lilis.xin/tags/gif/"/>
</entry>
<entry>
<title>gd-输出图片流</title>
<link href="https://hexo.lilis.xin/posts/faad097e/"/>
<id>https://hexo.lilis.xin/posts/faad097e/</id>
<published>2018-11-06T10:11:07.000Z</published>
<updated>2021-07-14T06:19:45.145Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>最近在搞laravels项目,由于laravels是通过swoole来加速laravel的,php-fpm模式下的一些输出函数受到了干扰,比如:header(),在laravels下返回输出和header头的设定需要由response()来完成.但是gd的输出就比较特别了,它要么输出网页,要么输出文件.如果想要输出二进制流再交给PHP就比较麻烦了,网上普遍的方案就是先把gd图像输出到缓存文件里,再读取出来.可是在要有占用了太多的磁盘I/O</p><a id="more"></a><h4 id="问题"><a class="header-anchor" href="#问题">➡️</a>问题</h4><p><code>gd</code>直接输出到网页我们后台无法很好的设置<code>header</code>来标注文件类型.</p><h4 id="方案"><a class="header-anchor" href="#方案">➡️</a>方案</h4><p><code>gd</code>先输出到文件,在用<code>file_get_contents</code>读取.<br>缺陷:太过于占用磁盘<code>I/O</code><br><code>gd</code>的输出先由<code>ob</code>缓存下来,再用<code>ob_get_contents</code>获取.<br>代码:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">ob_start();</span><br><span class="line"><span class="keyword">switch</span> (<span class="variable">$type</span>) {</span><br><span class="line"><span class="keyword">case</span> <span class="string">'jpg'</span>:</span><br><span class="line"><span class="keyword">case</span> <span class="string">'jpeg'</span>:</span><br><span class="line"><span class="variable">$type</span> = <span class="string">'image/jpeg'</span>;</span><br><span class="line">imagejpeg(<span class="keyword">$this</span>->image, <span class="string">''</span>, <span class="number">0.5</span>);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">case</span> <span class="string">'png'</span>:</span><br><span class="line"><span class="variable">$type</span> = <span class="string">'image/png'</span>;</span><br><span class="line">imagepng(<span class="keyword">$this</span>->image);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">case</span> <span class="string">'bmp'</span>:</span><br><span class="line"><span class="variable">$type</span> = <span class="string">'image/vnd.wap.wbmp'</span>;</span><br><span class="line">imagewbmp(<span class="keyword">$this</span>->image);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"><span class="keyword">case</span> <span class="string">'gif'</span>:</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line"><span class="variable">$type</span> = <span class="string">'image/gif'</span>;</span><br><span class="line">imagegif(<span class="keyword">$this</span>->image);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line"><span class="variable">$contents</span> = ob_get_contents();</span><br><span class="line">ob_end_clean();</span><br><span class="line"><span class="keyword">return</span> response(<span class="variable">$content</span>)</span><br><span class="line">->header(<span class="string">'Content-type'</span>, <span class="variable">$type</span>);</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>最近在搞laravels项目,由于laravels是通过swoole来加速laravel的,php-fpm模式下的一些输出函数受到了干扰,比如:header(),在laravels下返回输出和header头的设定需要由response()来完成.但是gd的输出就比较特别了,它要么输出网页,要么输出文件.如果想要输出二进制流再交给PHP就比较麻烦了,网上普遍的方案就是先把gd图像输出到缓存文件里,再读取出来.可是在要有占用了太多的磁盘I/O</p>
</summary>
<category term="PHP" scheme="https://hexo.lilis.xin/tags/PHP/"/>
<category term="gd" scheme="https://hexo.lilis.xin/tags/gd/"/>
<category term="ob" scheme="https://hexo.lilis.xin/tags/ob/"/>
</entry>
<entry>
<title>在Merlin上安装Entware</title>
<link href="https://hexo.lilis.xin/posts/32c6b91b/"/>
<id>https://hexo.lilis.xin/posts/32c6b91b/</id>
<published>2018-11-05T08:01:50.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>在之前安装好Merlin后,接下来就是安装Entware,不过在安装Entware之前需要先挂载U盘并格式化为ext4.</p><a id="more"></a><h3 id="安装fdisk"><a class="header-anchor" href="#安装fdisk">➡️</a>安装fdisk</h3><p>fdisk一般的Merlin都是自带的,无需安装,如果还没有安装fdisk而且也还没有Entware的话要么就直接用电脑格式化后挂载进去(这个我没有试过,应该效果一致)</p><h3 id="检查设备"><a class="header-anchor" href="#检查设备">➡️</a>检查设备</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">fdisk -l</span><br><span class="line"><span class="meta">#</span><span class="bash"> 这里先输出系统分区之类的不用管,外置设备一般在最后</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> 一般会有类似于这样的,如果没有那你需要检查一下U盘是否正常</span></span><br><span class="line">Disk /dev/sda: 30.7 GB, 30752000000 bytes</span><br><span class="line">64 heads, 32 sectors/track, 29327 cylinders</span><br></pre></td></tr></table></figure><p>上面的信息注意看到和你的存储大小一样的设备,我的是<code>/dev/sda</code>,在它里面有个<code>/dev/sda1</code>的分区</p><h3 id="删除并建立新的分区"><a class="header-anchor" href="#删除并建立新的分区">➡️</a>删除并建立新的分区</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">fdisk /dev/sda # 这是你的设备別打成分区,注意别打成了sda1</span><br><span class="line"></span><br><span class="line">Welcome to fdisk (util-linux 2.29.2).</span><br><span class="line">Changes will remain in memory only, until you decide to write them.</span><br><span class="line">Be careful before using the write command.</span><br><span class="line"></span><br><span class="line">Command (m for help): d # 输入d回车,我只有一个分区,它自动选择了,如果你有多个分区,可以多次使用d</span><br><span class="line">Selected partition 1</span><br><span class="line">Partition 1 has been deleted.</span><br><span class="line"></span><br><span class="line">Command (m for help): n # 输入n会车,创建分区</span><br><span class="line">Partition type</span><br><span class="line">p primary (0 primary, 0 extended, 4 free)</span><br><span class="line">e extended (container for logical partitions)</span><br><span class="line"></span><br><span class="line">Select (default p): p # 选择p</span><br><span class="line">Partition number (1-4, default 1): # 回车</span><br><span class="line">First sector (2048-2065023, default 2048): #回车</span><br><span class="line">Last sector, +sectors or +size{K,M,G,T,P} (2048-2065023, default 2065023): # 回车</span><br><span class="line">Created a new partition 1 of type 'Linux' and of size 1007.3 MiB.</span><br><span class="line"></span><br><span class="line">Command (m for help): w # 输入w回车,保存并退出</span><br><span class="line">The partition table has been altered.</span><br><span class="line">Calling ioctl() to re-read partition table.</span><br><span class="line">Syncing disks.</span><br></pre></td></tr></table></figure><p>经过以上的操作,你可以用<code>fdisk -l</code>命令查看U盘上是否只有一个<code>Linux</code>分区</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">fdisk -l</span><br><span class="line"><span class="meta">#</span><span class="bash"> 找到你的设备 可以看到ID为83就对了</span></span><br><span class="line">Disk /dev/sda: 30.7 GB, 30752000000 bytes</span><br><span class="line">64 heads, 32 sectors/track, 29327 cylinders</span><br><span class="line">Units = cylinders of 2048 * 512 = 1048576 bytes</span><br><span class="line">Device Boot Start End Blocks Id System</span><br><span class="line">/dev/sda1 2 29327 30029824 83 Linux</span><br></pre></td></tr></table></figure><h3 id="格式化分区"><a class="header-anchor" href="#格式化分区">➡️</a>格式化分区</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">mkfs.ext4 /dev/sda1</span><br><span class="line"><span class="meta">#</span><span class="bash"> 如果你的硬盘比较大,256G以上的话,是这个命令:mkfs.ext4 -T largefile /dev/sda1</span></span><br><span class="line">mke2fs 1.43.3 (04-Sep-2016)</span><br><span class="line">/dev/sda1 contains a ext4 file system labelled 'ONMP'</span><br><span class="line">last mounted on Sun Nov 12 09:21:22 2017</span><br><span class="line">Proceed anyway? (y,n) y # 输入y回车</span><br><span class="line">umount /dev/sda1 # 如果出错,可能是因为已经被挂载了,先执行这个卸载</span><br></pre></td></tr></table></figure><h3 id="挂载分区"><a class="header-anchor" href="#挂载分区">➡️</a>挂载分区</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">mkdir /mnt/sda1</span><br><span class="line">mount -t ext4 /dev/sda1 /mnt/sda1/</span><br><span class="line">df -h</span><br><span class="line">Filesystem Size Used Available Use% Mounted on</span><br><span class="line">/dev/sda1 975.5M 2.5M 906.6M 0% /tmp/mnt/sda1</span><br><span class="line"><span class="meta">#</span><span class="bash"> 可以看到已经挂载</span></span><br></pre></td></tr></table></figure><h3 id="安装和使用Entware"><a class="header-anchor" href="#安装和使用Entware">➡️</a>安装和使用Entware</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">entware-setup.sh</span><br></pre></td></tr></table></figure><p>注意一下选择分区的时候选择刚才挂载上去的那个<br>参考:</p><ul><li><a href="https://github.com/xzhih/ONMP/wiki/%E5%9C%A8%E6%A2%85%E6%9E%97%E4%B8%8A%E5%AE%89%E8%A3%85-Entware" title="在梅林上安装 Entware">在梅林上安装 Entware</a></li><li><a href="https://github.com/xzhih/ONMP/wiki/%E5%A6%82%E4%BD%95%E5%9C%A8%E8%B7%AF%E7%94%B1%E5%99%A8%E4%B8%8A%E6%A0%BC%E5%BC%8F%E5%8C%96-U-%E7%9B%98%E4%B8%BA-ext4" title="如何在路由器上格式化 U 盘为 ext4">如何在路由器上格式化 U 盘为 ext4</a></li></ul>]]></content>
<summary type="html">
<p>在之前安装好Merlin后,接下来就是安装Entware,不过在安装Entware之前需要先挂载U盘并格式化为ext4.</p>
</summary>
<category term="Merlin" scheme="https://hexo.lilis.xin/tags/Merlin/"/>
<category term="R7000" scheme="https://hexo.lilis.xin/tags/R7000/"/>
<category term="路由器" scheme="https://hexo.lilis.xin/tags/%E8%B7%AF%E7%94%B1%E5%99%A8/"/>
<category term="Entware" scheme="https://hexo.lilis.xin/tags/Entware/"/>
<category term="磁盘管理" scheme="https://hexo.lilis.xin/tags/%E7%A3%81%E7%9B%98%E7%AE%A1%E7%90%86/"/>
</entry>
<entry>
<title>R7000刷Merlin</title>
<link href="https://hexo.lilis.xin/posts/50136e28/"/>
<id>https://hexo.lilis.xin/posts/50136e28/</id>
<published>2018-11-05T05:56:02.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>之前买了一个Netgear R7000 路由器,到手后就感觉忍受不了它的那个超不好用的web ui,所以就没上手两分钟果断刷机成Merlin了.</p><a id="more"></a><h3 id="主要步骤"><a class="header-anchor" href="#主要步骤">➡️</a>主要步骤</h3><ol><li>刷机到<code>Merlin</code>和<code>Netgear</code>之间的一个过渡固件(这其实就是一些玩家做的<code>Netgear</code>版的<code>Merlin</code>固件包,是一个完整版的<code>Merlin</code>,只是版本比较老)</li><li>刷机到最新版的<code>Merlin</code></li></ol><h3 id="所需材料"><a class="header-anchor" href="#所需材料">➡️</a>所需材料</h3><p><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R7000_380.70_0-X7.9.1-koolshare.chk" title="R7000_380.70_0-X7.9.1-koolshare.chk">R7000_380.70_0-X7.9.1-koolshare.chk</a><br><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R7000_380.70_0-X7.9.1-koolshare.trx" title="R7000_380.70_0-X7.9.1-koolshare.trx">R7000_380.70_0-X7.9.1-koolshare.trx</a></p><h3 id="刷机方法"><a class="header-anchor" href="#刷机方法">➡️</a>刷机方法</h3><ul><li><a href="http://xn--www-0v1e42ucr2b2w5b9xj.routerlogin.net">浏览器输入www.routerlogin.net</a></li><li>进入<code>高级</code>—<code>管理</code>—<code>固件更新</code>,上传 <code>R7000_380.70_0-X7.9.1-koolshare.chk</code> 固件,点更新(有很多教程说要在这一步之前恢复出厂设置,不过我这边没有恢复也可以,如果有玩家不放心恢复出厂设置也可以)<br>更新固件过程中路由器可能要重启几次</li><li>再输入<a href="http://router.asus.com/" title="http://router.asus.com/">http://router.asus.com/</a>访问新的固件的控制面板</li><li>恢复一次出厂设置(这一次恢复出厂设置和格式化jffs分区也不是是必须的)</li><li>格式化jffs分区 进入路由管理界面 -<code>系统管理</code>- <code>系统设置</code>,勾选<code>Format JFFS partition at next boot</code>,点击应用本页面设置后重启路由器</li><li>进入路由器设置。<code>系统管理</code>—<code>固件升级</code>,选择 <code>R7000_380.70_0-X7.9.1-koolshare.trx</code> 上传后更新。</li><li>再恢复一次出厂设置就可以正常使用了</li></ul><h5 id="清配置说明"><a class="header-anchor" href="#清配置说明">➡️</a>清配置说明</h5><table><thead><tr><th>A 刷 B</th><th>(B)X6.x</th><th>(B)X7.x</th><th>(B)X7.9.1</th></tr></thead><tbody><tr><td>(A)X6.x</td><td>保持</td><td>清配置+格式化jffs</td><td>清配置+格式化jffs</td></tr><tr><td>(A)X7.x</td><td>清配置+格式化jffs</td><td>保持</td><td>保持</td></tr><tr><td>(A)X7.9.1</td><td>清配置+格式化jffs</td><td>仅格式化jffs</td><td>保持</td></tr></tbody></table><h5 id="固件双清方法"><a class="header-anchor" href="#固件双清方法">➡️</a>固件双清方法</h5><p>如果固件出现问题,一时找不到解决办法,可以尝试双清并手动配置,方法如下</p><ul><li>格式化jffs分区:方法同上;</li><li>恢复出厂设置:进入路由管理界面 -【【系统管理】- 【恢复/导出/上传设置】- 【原厂默认值】,点击原厂默认值一栏的【恢复】按钮;</li><li>建议完成双清后手动配置路由,而不是用以前备份的配置,以避免可能的问题;</li></ul><h3 id="资源下载"><a class="header-anchor" href="#资源下载">➡️</a>资源下载</h3><ul><li>X7.9.1 固件 (trx)</li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R6300V2_380.70_0-X7.9.1-koolshare.trx" title="R6300V2">R6300V2</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R6400_380.70_0-X7.9.1-koolshare.trx" title="R6400">R6400</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R7000_380.70_0-X7.9.1-koolshare.trx" title="R6900/R7000">R6900/R7000</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R8000_380.70_0-X7.9.1-koolshare.trx" title="R8000">R8000</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R8500_380.70_0-X7.9.1-koolshare.trx" title="R8500">R8500</a></li><li>X7.9.1 过渡固件 (chk)</li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R6300V2_380.70_0-X7.9.1-koolshare.chk" title="R6300V2">R6300V2</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R6400_380.70_0-X7.9.1-koolshare.chk" title="R6400">R6400</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R7000_380.70_0-X7.9.1-koolshare.chk" title="R6900/R7000">R6900/R7000</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R8000_380.70_0-X7.9.1-koolshare.chk" title="R8000">R8000</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R8500_380.70_0-X7.9.1-koolshare.chk" title="R8500">R8500</a></li><li>X7.9</li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R6300V2_380.70_0-X7.9-koolshare.trx" title="R6300V2">R6300V2</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R6400_380.70_0-X7.9-koolshare.trx" title="R6400">R6400</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R7000_380.70_0-X7.9-koolshare.trx" title="R6900/R7000">R6900/R7000</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R8000_380.70_0-X7.9-koolshare.trx" title="R8000">R8000</a></li><li><a href="https://blog.lilis.xin/pixivTop50/plugin/file/Router/R8500_380.70_0-X7.9-koolshare.trx" title="R8500">R8500</a></li></ul>]]></content>
<summary type="html">
<p>之前买了一个Netgear R7000 路由器,到手后就感觉忍受不了它的那个超不好用的web ui,所以就没上手两分钟果断刷机成Merlin了.</p>
</summary>
<category term="Merlin" scheme="https://hexo.lilis.xin/tags/Merlin/"/>
<category term="R7000" scheme="https://hexo.lilis.xin/tags/R7000/"/>
<category term="路由器" scheme="https://hexo.lilis.xin/tags/%E8%B7%AF%E7%94%B1%E5%99%A8/"/>
</entry>
<entry>
<title>测试Emoji表情</title>
<link href="https://hexo.lilis.xin/posts/5cd7067a/"/>
<id>https://hexo.lilis.xin/posts/5cd7067a/</id>
<published>2018-10-29T13:43:42.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>🐰 🐨 🐸 🐞 🐾 😄 💙✈️👶🐤🎈🐻🌵👯😰🍂💋🎃🐙</p>]]></content>
<summary type="html">
<script src="/assets/js/APlayer.min.js"> </script><p>🐰 🐨 🐸 🐞 🐾 😄 💙✈️👶🐤🎈🐻🌵👯😰🍂💋🎃🐙</p>
</summary>
<category term="emoji" scheme="https://hexo.lilis.xin/tags/emoji/"/>
</entry>
<entry>
<title>LaravelS开发记录</title>
<link href="https://hexo.lilis.xin/posts/45ef7ac/"/>
<id>https://hexo.lilis.xin/posts/45ef7ac/</id>
<published>2018-10-29T08:35:19.000Z</published>
<updated>2019-09-13T07:34:45.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>主要记录了由普通PHP开发者初步接触laravelS是所遇到的一些小坑</p><a id="more"></a><h3 id="LaravelS介绍"><a class="header-anchor" href="#LaravelS介绍">➡️</a>LaravelS介绍</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"> _ _ _____</span><br><span class="line">| | | |/ ____|</span><br><span class="line">| | __ _ _ __ __ ___ _____| | (___</span><br><span class="line">| | / _` | '__/ _` \ \ / / _ \ |\___ \</span><br><span class="line">| |___| (_| | | | (_| |\ V / __/ |____) |</span><br><span class="line">|______\__,_|_| \__,_| \_/ \___|_|_____/</span><br></pre></td></tr></table></figure><p>LaravelS是一个能够使普通的laravel项目尽快的享受上swoole的优势的laravel插件<br>官方描述:<br>🚀LaravelS是一个胶水项目,用于快速集成Swoole到Laravel或Lumen,然后赋予它们更好的性能、更多可能性。</p><p>GitHub地址:</p><div style="text-align: center"> <div class="github-card" data-user="hhxsv5" data-repo="laravel-s" data-height="200px" data-width="100%" data-theme="default" data-target="blank" data-client-id data-client-secret></div></div><script src="/github-card-lib/githubcard.js"></script><p>文档地址:<br><a href="https://github.com/hhxsv5/laravel-s/blob/master/README-CN.md" title="laravel-s/README-CN.md">laravel-s/README-CN.md</a><br>Laravel-China地址:<br><a href="https://laravel-china.org/articles/8050/laravels-speed-up-laravellumen-through-swoole" title="LaravelS - 基于 Swoole 加速 Laravel/Lumen - 带你飞 🚀">LaravelS - 基于 Swoole 加速 Laravel/Lumen - 带你飞 🚀</a></p><h3 id="安装"><a class="header-anchor" href="#安装">➡️</a>安装</h3><h4 id="安装要求"><a class="header-anchor" href="#安装要求">➡️</a>安装要求</h4><table><thead><tr><th>依赖</th><th>说明</th></tr></thead><tbody><tr><td>PHP</td><td>>= 5.5.9 推荐PHP7+</td></tr><tr><td>Swoole</td><td>>= 1.7.19 从2.0.12开始不再支持PHP5 推荐4.2.3+</td></tr><tr><td>Laravel/Lumen</td><td>>= 5.1 推荐5.6+</td></tr></tbody></table><h4 id="安装swoole"><a class="header-anchor" href="#安装swoole">➡️</a>安装swoole</h4><p>详细请参考 <a href="https://hexo.lilis.xin/2018/07/26/install-swoole/" title="swoole安装">swoole安装</a></p><h4 id="安装laravel"><a class="header-anchor" href="#安装laravel">➡️</a>安装laravel</h4><p>可以通过composer直接安装,或者安装安装器或者直接从GitHub拷贝源代码来安装</p><h4 id="安装laravelS"><a class="header-anchor" href="#安装laravelS">➡️</a>安装laravelS</h4><ol><li>通过Composer安装</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">composer require "hhxsv5/laravel-s:~3.0" -vvv</span><br><span class="line"><span class="meta">#</span><span class="bash"> 确保你的composer.lock文件是在版本控制中</span></span><br></pre></td></tr></table></figure><ol start="2"><li>注册<code>Service Provider</code><ul><li>Laravel: 修改文件<code>config/app.php</code>,Laravel 5.5+支持包自动发现,你应该跳过这步</li></ul></li></ol><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">'providers'</span> => [</span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line"> Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class,</span><br><span class="line">],</span><br></pre></td></tr></table></figure><pre><code>- Lumen: 修改文件`bootstrap/app.php`</code></pre><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$app</span>->register(Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class);</span><br></pre></td></tr></table></figure><ol start="3"><li>发布配置文件.</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php artisan laravels publish</span><br></pre></td></tr></table></figure><p>如果你用的是<code>lumen</code>,不需要加载<code>config/laravels.php</code></p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//这个可有可无</span></span><br><span class="line"><span class="variable">$app</span>->configure(<span class="string">'laravels'</span>);</span><br></pre></td></tr></table></figure><ol start="4"><li>修改配置<code>config/laravels.php</code><br>请参考<code>laravelS配置项</code></li></ol><h4 id="运行"><a class="header-anchor" href="#运行">➡️</a>运行</h4><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php artisan laravels {start|stop|restart|reload|publish}</span><br></pre></td></tr></table></figure><table><thead><tr><th>命令</th><th>说明</th></tr></thead><tbody><tr><td>start</td><td>启动<code>LaravelS</code>。选项<code>-d</code>或<code>--daemonize</code>以守护进程的方式运行,此选项将覆盖<code>laravels.php</code>中<code>swoole.daemonize</code>设置</td></tr><tr><td>stop</td><td>停止<code>LaravelS</code></td></tr><tr><td>restart</td><td>重启<code>LaravelS</code>,支持选项<code>-d</code>或<code>--daemonize</code></td></tr><tr><td>reload</td><td>平滑重启所有<code>worker</code>进程,这些<code>worker</code>进程内包含你的业务代码和框架(<code>Laravel/Lumen</code>)代码,不会重启<code>master/manger</code>进程</td></tr><tr><td>publish</td><td>发布配置文件到你的项目中<code>config/laravels.php</code></td></tr></tbody></table><p>ps:展示已经启动的项目:<br><code>ps -ef|grep laravels</code></p><h4 id="配置nginx"><a class="header-anchor" href="#配置nginx">➡️</a>配置nginx</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line">gzip on;</span><br><span class="line">gzip_min_length 1024;</span><br><span class="line">gzip_comp_level 2;</span><br><span class="line">gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml;</span><br><span class="line">gzip_vary on;</span><br><span class="line">gzip_disable "msie6";</span><br><span class="line">upstream laravels {</span><br><span class="line"> # By IP:Port</span><br><span class="line"> server 127.0.0.1:9100 weight=5 max_fails=3 fail_timeout=30s; #这里配置的是laravelS监听的接口参数</span><br><span class="line"> # By UnixSocket Stream file</span><br><span class="line"> #server unix:/xxxpath/laravel-s-test/storage/laravels.sock weight=5 max_fails=3 fail_timeout=30s;</span><br><span class="line"> #server 192.168.1.1:5200 weight=3 max_fails=3 fail_timeout=30s;</span><br><span class="line"> #server 192.168.1.2:5200 backup;</span><br><span class="line">}</span><br><span class="line">server {</span><br><span class="line">listen 80;</span><br><span class="line">server_name laravels.com;</span><br><span class="line"><span class="meta">#</span><span class="bash">为了给nginx定位静态资源</span></span><br><span class="line">root /xxxpath/laravel-s-test/public;</span><br><span class="line"><span class="meta">#</span><span class="bash"> Nginx处理静态资源(建议开启gzip),LaravelS处理动态资源。</span></span><br><span class="line">location / {</span><br><span class="line">try_files $uri @laravels;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">location @laravels {</span><br><span class="line"> proxy_connect_timeout 60s;</span><br><span class="line"> proxy_send_timeout 60s;</span><br><span class="line"> proxy_read_timeout 120s;</span><br><span class="line"> proxy_set_header Connection "keep-alive";</span><br><span class="line"> proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line"> proxy_set_header X-Real-PORT $remote_port;</span><br><span class="line"> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br><span class="line"> proxy_set_header Host $http_host;</span><br><span class="line"> proxy_set_header Scheme $scheme;</span><br><span class="line"> proxy_set_header Server-Protocol $server_protocol;</span><br><span class="line"> proxy_set_header Server-Name $server_name;</span><br><span class="line"> proxy_set_header Server-Addr $server_addr;</span><br><span class="line"> proxy_set_header Server-Port $server_port;</span><br><span class="line"> proxy_pass http://laravels;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="配置Apache"><a class="header-anchor" href="#配置Apache">➡️</a>配置Apache</h4><p>ps:我用的是nginx,没有实际配置过,就直接把官方文档里的拿过来了</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">LoadModule proxy_module /yyypath/modules/mod_deflate.so</span><br><span class="line"><span class="tag"><<span class="name">IfModule</span> <span class="attr">deflate_module</span>></span></span><br><span class="line"> SetOutputFilter DEFLATE</span><br><span class="line"> DeflateCompressionLevel 2</span><br><span class="line"> AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml</span><br><span class="line"><span class="tag"></<span class="name">IfModule</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">VirtualHost</span> *<span class="attr">:80</span>></span></span><br><span class="line"> # 别忘了绑Host哟</span><br><span class="line"> ServerName www.laravels.com</span><br><span class="line"> ServerAdmin hhxsv5@sina.com</span><br><span class="line"></span><br><span class="line"> DocumentRoot /xxxpath/laravel-s-test/public;</span><br><span class="line"> DirectoryIndex index.html index.htm</span><br><span class="line"> <span class="tag"><<span class="name">Directory</span> "/"></span></span><br><span class="line"> AllowOverride None</span><br><span class="line"> Require all granted</span><br><span class="line"> <span class="tag"></<span class="name">Directory</span>></span></span><br><span class="line"></span><br><span class="line"> LoadModule proxy_module /yyypath/modules/mod_proxy.so</span><br><span class="line"> LoadModule proxy_module /yyypath/modules/mod_proxy_balancer.so</span><br><span class="line"> LoadModule proxy_module /yyypath/modules/mod_lbmethod_byrequests.so.so</span><br><span class="line"> LoadModule proxy_module /yyypath/modules/mod_proxy_http.so.so</span><br><span class="line"> LoadModule proxy_module /yyypath/modules/mod_slotmem_shm.so</span><br><span class="line"> LoadModule proxy_module /yyypath/modules/mod_rewrite.so</span><br><span class="line"></span><br><span class="line"> ProxyRequests Off</span><br><span class="line"> ProxyPreserveHost On</span><br><span class="line"> <span class="tag"><<span class="name">Proxy</span> <span class="attr">balancer:</span>//<span class="attr">laravels</span>></span></span><br><span class="line"> BalancerMember http://192.168.1.1:8011 loadfactor=7</span><br><span class="line"> #BalancerMember http://192.168.1.2:8011 loadfactor=3</span><br><span class="line"> #BalancerMember http://192.168.1.3:8011 loadfactor=1 status=+H</span><br><span class="line"> ProxySet lbmethod=byrequests</span><br><span class="line"> <span class="tag"></<span class="name">Proxy</span>></span></span><br><span class="line"> #ProxyPass / balancer://laravels/</span><br><span class="line"> #ProxyPassReverse / balancer://laravels/</span><br><span class="line"></span><br><span class="line"> # Apache处理静态资源,LaravelS处理动态资源。</span><br><span class="line"> RewriteEngine On</span><br><span class="line"> RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d</span><br><span class="line"> RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f</span><br><span class="line"> RewriteRule ^/(.*)$ balancer://laravels/%{REQUEST_URI} [P,L]</span><br><span class="line"></span><br><span class="line"> ErrorLog ${APACHE_LOG_DIR}/www.laravels.com.error.log</span><br><span class="line"> CustomLog ${APACHE_LOG_DIR}/www.laravels.com.access.log combined</span><br><span class="line"><span class="tag"></<span class="name">VirtualHost</span>></span></span><br></pre></td></tr></table></figure><h4 id="自定义的异步任务"><a class="header-anchor" href="#自定义的异步任务">➡️</a>自定义的异步任务</h4><p>此特性依赖<code>Swoole</code>的<code>AsyncTask</code>,必须先设置<code>config/laravels.php</code>的<code>swoole.task_worker_num</code>。<br>异步事件的处理能力受<code>Task</code>进程数影响,需合理设置<code>task_worker_num</code>。<br>任务结构</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">namespace</span> <span class="title">App</span>\<span class="title">Task</span>\<span class="title">Message</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">App</span>\<span class="title">Traits</span>\<span class="title">Push</span>;</span><br><span class="line"><span class="keyword">use</span> <span class="title">Hhxsv5</span>\<span class="title">LaravelS</span>\<span class="title">Swoole</span>\<span class="title">Task</span>\<span class="title">Task</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Reply</span> <span class="keyword">extends</span> <span class="title">Task</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="variable">$data</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">__construct</span>(<span class="params"><span class="variable">$data</span></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">$this</span>->data = <span class="variable">$data</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 任务逻辑</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">handle</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"><span class="comment">//Do something</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>ps: 任务里没有依赖注入这种便捷的东西<br>投递任务</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 实例化$action并通过deliver投递</span></span><br><span class="line"><span class="comment">//此操作是异步的,投递后立即返回</span></span><br><span class="line"><span class="comment">//由Task进程继续处理$action中的handle逻辑</span></span><br><span class="line"><span class="variable">$task</span> = <span class="keyword">new</span> \App\Task\Message\Reply(<span class="variable">$dat</span>);</span><br><span class="line"><span class="comment">// $task->delay(3);// 延迟3秒投放任务</span></span><br><span class="line">\Hhxsv5\LaravelS\Swoole\Task\Task::deliver(<span class="variable">$task</span>);</span><br></pre></td></tr></table></figure><h4 id="laravelS配置项"><a class="header-anchor" href="#laravelS配置项">➡️</a>laravelS配置项</h4><ul><li><p><code>listen_ip</code>:<code>string</code> 监听的IP,监听本机<code>127.0.0.1</code>(IPv4) <code>::1</code>(IPv6),监听所有地址 <code>0.0.0.0</code>(IPv4) ::(IPv6), 默认<code>127.0.0.1</code>。</p></li><li><p><code>listen_port</code>:<code>int</code> 监听的端口,如果端口小于1024则需要root权限,<code>default 5200</code>。</p></li><li><p><code>socket_type</code>:默认<code>SWOOLE_SOCK_TCP</code>。通常情况下,无需关心这个配置。若需Nginx代理至<code>UnixSocket Stream</code>文件,则需修改为<code>SWOOLE_SOCK_UNIX_STREAM</code>,此时<code>listen_ip</code>则是<code>UnixSocket Stream</code>文件的路径。</p></li><li><p><code>enable_gzip</code>:bool 当通过LaravelS响应数据时,是否启用gzip压缩响应的内容,依赖库<code>zlib</code>,通过命令<code>php --ri swoole|grep zlib</code>检查<code>gzip</code>是否可用。如果开启则会自动加上头部<code>Content-Encoding</code>,默认<code>false</code>。如果存在代理服务器(例如Nginx),建议代理服务器开启<code>gzip</code>,<code>LaravelS</code>关闭gzip,避免重复<code>gzip</code>压缩。</p></li><li><p><code>server</code>:<code>string</code> 当通过<code>LaravelS</code>响应数据时,设置<code>HTTP</code>头部<code>Server</code>的值,若为空则不设置,<code>default LaravelS</code>。</p></li><li><p><code>handle_static</code>:<code>bool</code> 是否开启<code>LaravelS</code>处理静态资源(要求 <code>Swoole >= 1.7.21</code>,若<code>Swoole >= 1.9.17</code>则由Swoole自己处理),默认<code>false</code>,建议<code>Nginx</code>处理静态资源,<code>LaravelS</code>仅处理动态资源。静态资源的默认路径为<code>base_path('public')</code>,可通过修改<code>swoole.document_root</code>变更。</p></li><li><p><code>laravel_base_path</code>:<code>string</code> <code>Laravel/Lumen</code>的基础路径,默认<code>base_path()</code>,可用于配置符号链接。</p></li><li><p><code>inotify_reload.enable</code>:<code>bool</code> 是否开启<code>Inotify Reload</code>,用于当修改代码后实时<code>Reload</code>所有<code>worker</code>进程,依赖库<code>inotify</code>,通过命令<code>php --ri inotify</code>检查是否可用,默认<code>false</code>,建议仅开发环境开启,修改监听数上限。</p></li><li><p><code>inotify_reload.watch_path</code>:<code>string</code> <code>Inotify</code> 监控的文件路径,默认有<code>base_path()</code>。</p></li><li><p><code>inotify_reload.file_types</code>:<code>array</code> <code>Inotify</code> 监控的文件类型,默认有<code>.php</code>。</p></li><li><p><code>inotify_reload.log</code>:<code>bool</code> 是否输出<code>Reload</code>的日志,默认<code>true</code>。</p></li><li><p><code>websocket.enable</code>:<code>bool</code> 是否启用<code>WebSocket</code>服务器。启用后<code>WebSocket</code>服务器监听的<code>IP</code>和端口与<code>Http</code>服务器相同,默认<code>false</code>。</p></li><li><p><code>websocket.handler</code>:<code>string</code> <code>WebSocket</code>逻辑处理的类名,需实现接口<code>WebSocketHandlerInterface</code>,参考示例。</p></li><li><p><code>sockets</code>:<code>array</code> 配置<code>TCP/UDP</code>套接字列表,参考示例。</p></li><li><p><code>processes</code>:<code>array</code> 配置自定义进程列表,参考示例。</p></li><li><p><code>events</code>:<code>array</code> 自定义的异步事件和监听的绑定列表,参考示例。</p></li><li><p><code>swoole_tables</code>:<code>array</code> 定义的<code>swoole_table</code>列表,参考示例。</p></li><li><p><code>register_providers</code>:<code>array</code> 每次请求需要重新注册的<code>Service Provider</code>列表,若存在<code>boot()</code>方法,会自动执行。一般用于清理注册了单例的<code>ServiceProvider</code>。</p></li></ul><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//...</span></span><br><span class="line"><span class="string">'register_providers'</span> => [</span><br><span class="line"> <span class="comment">//例如:重新注册jwt的ServiceProvider</span></span><br><span class="line"> \Tymon\JWTAuth\Providers\LaravelServiceProvider::class,</span><br><span class="line">],</span><br><span class="line"><span class="comment">//...</span></span><br></pre></td></tr></table></figure><ul><li>swoole:<code>array</code> <code>Swoole</code>的原始配置项,请参考<a href="https://wiki.swoole.com/wiki/page/274.html" title="Swoole配置项">Swoole配置项</a>。</li></ul>]]></content>
<summary type="html">
<p>主要记录了由普通PHP开发者初步接触laravelS是所遇到的一些小坑</p>
</summary>
<category term="PHP" scheme="https://hexo.lilis.xin/tags/PHP/"/>
<category term="异步" scheme="https://hexo.lilis.xin/tags/%E5%BC%82%E6%AD%A5/"/>
<category term="laravel" scheme="https://hexo.lilis.xin/tags/laravel/"/>
<category term="LaravelS" scheme="https://hexo.lilis.xin/tags/LaravelS/"/>
<category term="Lumen" scheme="https://hexo.lilis.xin/tags/Lumen/"/>
<category term="swoole" scheme="https://hexo.lilis.xin/tags/swoole/"/>
</entry>
<entry>
<title>php在linux下call to undefined function imagettftext()</title>
<link href="https://hexo.lilis.xin/posts/d90db6f7/"/>
<id>https://hexo.lilis.xin/posts/d90db6f7/</id>
<published>2018-09-19T11:13:43.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>在线上环境测试图片生成的时候报错:<code>call to undefined function imagettftext()</code></p><a id="more"></a><h4 id="解决方案"><a class="header-anchor" href="#解决方案">➡️</a>解决方案</h4><p>下载安装<a href="https://sourceforge.net/projects/freetype/files/freetype2/2.7.1/freetype-2.7.1.tar.gz/download" title="freetype">freetype</a></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">./configure --prefix=/usr/local/freetype/2.7.1 --without-harfbuzz //编译</span><br><span class="line">make</span><br><span class="line">make install</span><br></pre></td></tr></table></figure><p>再重新编译安装gd</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">phpize</span><br><span class="line">make clean</span><br><span class="line">./configure --with-php-config=/usr/local/php/php72/bin/php-config--with-freetype-dir=/usr/local/freetype/2.7.1/ --enable-gd-native-ttf</span><br><span class="line">make</span><br><span class="line">make install</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>在线上环境测试图片生成的时候报错:<code>call to undefined function imagettftext()</code></p>
</summary>
<category term="gd" scheme="https://hexo.lilis.xin/tags/gd/"/>
<category term="freetype" scheme="https://hexo.lilis.xin/tags/freetype/"/>
</entry>
<entry>
<title>php操作redis</title>
<link href="https://hexo.lilis.xin/posts/a8f30b9a/"/>
<id>https://hexo.lilis.xin/posts/a8f30b9a/</id>
<published>2018-09-19T03:32:16.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>这里主要是用的predis</p><a id="more"></a><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//验证是否安装OK:打开dos窗口->输入redis-server 在打开一个dos窗口-->输入redis-cli 显示:127.0.0.1:6379>则成功!</span></span><br><span class="line"><span class="variable">$redis</span> = <span class="keyword">new</span> redis();</span><br><span class="line"><span class="variable">$redis</span>->connect(<span class="string">'127.0.0.1'</span>, <span class="string">'6379'</span>) || <span class="keyword">die</span>(<span class="string">"连接失败!"</span>);</span><br><span class="line"><span class="variable">$redis</span>->auth(<span class="string">"admin"</span>); <span class="comment">//授权</span></span><br><span class="line"><span class="comment">//******************************string类型**********************************************************</span></span><br><span class="line"><span class="comment">//String 是最简单的类型,一个Key对应一个Value,String类型是二进制安全的。Redis的String可以包含任何数据,比如jpg图片或者序列化的对象</span></span><br><span class="line"><span class="variable">$redis</span>->set(<span class="string">'test'</span>, <span class="number">200</span>); <span class="comment">//赋值</span></span><br><span class="line"><span class="variable">$redis</span>->mset(<span class="keyword">array</span>(<span class="string">'key0'</span> => <span class="string">'value0'</span>, <span class="string">'key1'</span> => <span class="string">'value1'</span>));<span class="comment">//批量赋值</span></span><br><span class="line"><span class="variable">$redis</span>->mget(<span class="keyword">array</span>(<span class="string">'key0'</span>, <span class="string">'key1'</span>, <span class="string">'key2'</span>));<span class="comment">//批量获取值</span></span><br><span class="line"><span class="variable">$redis</span>->setnx(<span class="string">'key'</span>,value);<span class="comment">//设置key对应的值为string类型的value,如果key已经存在,返回0,nx是not exist的意思</span></span><br><span class="line"><span class="variable">$redis</span>->msetnx(<span class="keyword">array</span>(<span class="string">'key0'</span> => <span class="string">'value0'</span>, <span class="string">'key1'</span> => <span class="string">'value1'</span>));<span class="comment">//全部成功返回1,否则失败一个也返回0</span></span><br><span class="line"><span class="variable">$redis</span>->getset(<span class="string">"key"</span>,<span class="string">'newvalue'</span>);<span class="comment">//getset设置key的值,并返回key的旧值</span></span><br><span class="line"><span class="variable">$redis</span>->setex(<span class="string">'key'</span>,<span class="number">10</span>,<span class="string">'value10'</span>);<span class="comment">//带生存时间的写入值单位s</span></span><br><span class="line"><span class="variable">$redis</span>->setrange(<span class="string">'key'</span>,<span class="number">0</span>,<span class="string">'hello'</span>);<span class="comment">//设置子字符串替换,key,开始位置,替换值</span></span><br><span class="line"><span class="variable">$redis</span>->getrange(<span class="string">"key"</span>,<span class="number">0</span>,<span class="number">2</span>);<span class="comment">//getrange获取子字符串,getrange key start end</span></span><br><span class="line"><span class="variable">$redis</span>->ttl(<span class="string">'key'</span>);<span class="comment">//获取key的生存时间,没设置的为-1</span></span><br><span class="line"><span class="variable">$redis</span>->keys(<span class="string">"*a*"</span>);<span class="comment">//获取所有key,也可获取具体key,模糊匹配key</span></span><br><span class="line"><span class="variable">$redis</span>->get(<span class="string">"test"</span>); <span class="comment">//根据key获取value</span></span><br><span class="line"><span class="variable">$redis</span>->getMultiple(<span class="keyword">array</span>(<span class="string">'key1'</span>, <span class="string">'key2'</span>, <span class="string">'key3'</span>));</span><br><span class="line"><span class="variable">$exits</span> = <span class="variable">$redis</span>->exists(<span class="string">'test'</span>); <span class="comment">//判断key是否存在。存在 true 不存在 false</span></span><br><span class="line"><span class="keyword">echo</span> <span class="variable">$exists</span>?<span class="variable">$res2</span>:<span class="string">"null"</span>;</span><br><span class="line"><span class="keyword">echo</span> <span class="variable">$res1</span>?<span class="variable">$res2</span>:<span class="string">"null"</span>;<span class="keyword">die</span>;</span><br><span class="line"><span class="variable">$redis</span>->delete(<span class="string">'key1'</span>, <span class="string">'key2'</span>); <span class="comment">//删除,可删除多个</span></span><br><span class="line"><span class="variable">$redis</span>->delete(<span class="keyword">array</span>(<span class="string">'key3'</span>, <span class="string">'key4'</span>, <span class="string">'key5'</span>));<span class="comment">//删除,可删除多个</span></span><br><span class="line"><span class="variable">$redis</span>->delete( <span class="variable">$redis</span>->keys(<span class="string">"*"</span>));<span class="comment">//传数组,删除所有key</span></span><br><span class="line"><span class="variable">$redis</span>->incr(<span class="string">"key"</span>,<span class="number">1</span>);<span class="comment">//自增,默认值1</span></span><br><span class="line"><span class="variable">$redis</span>->incrBy(<span class="string">'key'</span>,<span class="number">10</span>);<span class="comment">//必须给定参数值</span></span><br><span class="line"><span class="variable">$redis</span>->decr(<span class="string">"key"</span>,<span class="number">10</span>);<span class="comment">//自减,默认值1</span></span><br><span class="line"><span class="variable">$redis</span>->decrBy(<span class="string">'key'</span>,<span class="number">10</span>);<span class="comment">//必须给定参数值</span></span><br><span class="line"><span class="variable">$redis</span>->append(<span class="string">"key"</span>,<span class="string">"appendvalue"</span>);<span class="comment">//给指定的key的字符串追加value,返回新字符串的长度</span></span><br><span class="line"><span class="variable">$redis</span>->strlen(<span class="string">'key'</span>);<span class="comment">//获取指定key的字符串长度</span></span><br><span class="line"><span class="comment">//******************************string类型**********************************************************</span></span><br><span class="line"><span class="comment">//******************************hash类型**********************************************************</span></span><br><span class="line"><span class="comment">// Redis hash是一个string类型的field和value的映射表。它的添加删除都是0(1)</span></span><br><span class="line"><span class="comment">// hash特别适合用于存储对象。相对于将对象的每个字段存成单个string类型。</span></span><br><span class="line"><span class="comment">//将一个对象存储在hash类型中会占用更少的内存,并且可以更方便的存取整个对象。</span></span><br><span class="line"><span class="variable">$redis</span>->flushall();<span class="keyword">die</span>;<span class="comment">//清空所有数据库</span></span><br><span class="line"> <span class="variable">$redis</span>->flushdb();<span class="keyword">die</span>;<span class="comment">//清空当前数据库</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="variable">$redis</span>->hset(<span class="string">"test"</span>,<span class="string">"username"</span>,<span class="string">"admin"</span>);<span class="comment">//单个设置</span></span><br><span class="line"><span class="variable">$redis</span>->hget(<span class="string">"test"</span>,<span class="string">"username"</span>);<span class="comment">//单个获取</span></span><br><span class="line"><span class="variable">$redis</span>->hsetnx(<span class="string">"test"</span>,<span class="string">"username"</span>,<span class="string">"admin@qq.com"</span>);<span class="comment">//设置hash field 为指定的值value,如果feild已经存在,返回0,nx是not exist的意思 </span></span><br><span class="line"><span class="variable">$redis</span>->hmset(<span class="string">"testabc"</span>,<span class="keyword">array</span>(<span class="string">"a"</span>=><span class="number">1</span>,<span class="string">"b"</span>=><span class="number">2</span>,<span class="string">"c"</span>=><span class="number">3</span>,<span class="string">'d'</span>=><span class="number">4</span>));<span class="comment">//批量设置</span></span><br><span class="line"><span class="variable">$redis</span>->hmget(<span class="string">"testabc"</span>,<span class="keyword">array</span>(<span class="string">"a"</span>,<span class="string">"b"</span>,<span class="string">"c"</span>));<span class="comment">//批量获取</span></span><br><span class="line"><span class="variable">$redis</span>->hincrBy(<span class="string">"test"</span>,<span class="string">"password"</span>,<span class="string">"123456"</span>);<span class="comment">//设置hash field 添加key和value</span></span><br><span class="line"><span class="variable">$redis</span>->hexists(<span class="string">"test"</span>,<span class="string">"usernames"</span>);<span class="comment">//测试hash field 存在1,不存在0</span></span><br><span class="line"><span class="variable">$redis</span>->hlen(<span class="string">"test"</span>); <span class="comment">//返回hash 里所有的 field 的数量</span></span><br><span class="line"><span class="variable">$redis</span>->hdel(<span class="string">"test"</span>,<span class="string">"key"</span>);<span class="comment">//删除指定hash的field</span></span><br><span class="line"><span class="variable">$redis</span>->hkeys(<span class="string">"test"</span>); <span class="comment">//返回hash 所有 field</span></span><br><span class="line"><span class="variable">$redis</span>->hvals(<span class="string">"test"</span>);<span class="comment">//返回hash 所有 field values</span></span><br><span class="line"><span class="variable">$redis</span>->hgetall(<span class="string">"test"</span>);<span class="comment">//获取hash中全部的field和value</span></span><br><span class="line"><span class="comment">//******************************hash类型**********************************************************</span></span><br><span class="line"><span class="comment">//******************************list链表**********************************************************</span></span><br><span class="line"><span class="comment">//栈先进后出;队列先进先出;</span></span><br><span class="line"><span class="comment">//List 是一个链表结构,主要功能是push,pop,获取一个范围的所有值等等,操作中key理解为链表的名字。</span></span><br><span class="line"><span class="comment">//Redis的list类型其实就是一个每个子元素都是string类型的双向链表。我们可以通过push,pop操作从链表的头部或者尾部添加删除元素,这样LIST既可以作为栈,又可以作为队列。</span></span><br><span class="line"><span class="variable">$redis</span>->lrange(<span class="string">"list"</span>,<span class="number">0</span>,<span class="number">-1</span>);<span class="comment">//取链表list 从0位开始取到最后位置;0代表头 -1代表尾</span></span><br><span class="line"><span class="variable">$redis</span>->lpush(<span class="string">"list"</span>,<span class="string">"1"</span>); <span class="comment">//在key对应的list的头部添加字符串元素</span></span><br><span class="line"><span class="variable">$redis</span>->rpush(<span class="string">"list"</span>,<span class="string">"test"</span>); <span class="comment">//在key对应的list的尾部添加字符串元素</span></span><br><span class="line"><span class="variable">$redis</span>->lpop(<span class="string">"list"</span>);<span class="comment">//在key对应的list的头部删除字符串元素,并返回删除字符</span></span><br><span class="line"><span class="variable">$redis</span>->rpop(<span class="string">"list"</span>);<span class="comment">//在key对应的list的尾部删除字符串元素,并返回删除字符</span></span><br><span class="line"><span class="keyword">echo</span> <span class="variable">$redis</span>->lrem(<span class="string">"list"</span>,<span class="number">2</span>,<span class="string">'key'</span>);<span class="comment">//在list中删除N个和value相同的元素(n<0从尾删除,n=0全部删除),返回的值为删除的个数</span></span><br><span class="line"><span class="variable">$redis</span>->lset(<span class="string">"list"</span>,<span class="number">-1</span>,<span class="string">"啊"</span>);<span class="comment">//设置list中指定下标的元素值 lset(list,位置,值),位置可以从头或者从尾</span></span><br><span class="line"><span class="variable">$redis</span>->lindex(<span class="string">"list"</span>,<span class="number">0</span>);<span class="comment">//返回list中index位置的元素</span></span><br><span class="line"><span class="variable">$redis</span>->llen(<span class="string">"list"</span>);<span class="comment">//返回list的长度</span></span><br><span class="line"><span class="variable">$redis</span>->ltrim(<span class="string">"list"</span>,<span class="number">0</span>,<span class="number">1</span>);<span class="comment">//保留指定key的值的范围内的数据 0为头 -1为尾</span></span><br><span class="line"><span class="variable">$redis</span>->linsert(<span class="string">"list"</span>);<span class="comment">//********</span></span><br><span class="line"><span class="variable">$redis</span>->rpoplpush(<span class="string">"list"</span>,<span class="string">"listt"</span>);<span class="comment">//从第一个LIST的尾部移除元素并添加到第二个LIST的头部</span></span><br><span class="line"><span class="comment">//******************************list链表**********************************************************</span></span><br><span class="line"><span class="comment">//******************************set集合**********************************************************</span></span><br><span class="line"><span class="comment">// Set是集合,它是string类型的无序集合。set是通过hash table实现的,添加,删除和查找的复杂程度都是0(1)</span></span><br><span class="line"><span class="comment">// 对集合我们可以取并集,交集,差集。通过这些操作我们可以实现SNS中的好友推荐和blog的tag功能</span></span><br><span class="line"><span class="variable">$redis</span>->sadd(<span class="string">"col"</span>,<span class="string">"a"</span>,<span class="string">"b"</span>,<span class="string">"c"</span>);<span class="comment">//向集合中添加元素</span></span><br><span class="line"><span class="variable">$redis</span>->smembers(<span class="string">"col"</span>);<span class="comment">//集合元素列表</span></span><br><span class="line"><span class="variable">$redis</span>->srem(<span class="string">"col"</span>,<span class="string">'d'</span>);<span class="comment">//集合移除元素</span></span><br><span class="line"><span class="variable">$redis</span>->spop(<span class="string">"col"</span>);<span class="comment">//随机删除集合元素并返回删除的元素。删除最后一个元素时,则集合也被删除</span></span><br><span class="line"><span class="variable">$redis</span>->sdiff(<span class="string">"set1"</span>,<span class="string">"set2"</span>);<span class="comment">//取多个集合的差集,谁在前面已谁为标准(差集就是前面第一个集合有而后面所有集合都没有)</span></span><br><span class="line"><span class="variable">$redis</span>->sdiffstore(<span class="string">"dif"</span>,<span class="string">"set1"</span>,<span class="string">"set2"</span>);<span class="comment">//返回多个集合的差集,存在第三个集合里面</span></span><br><span class="line"><span class="variable">$redis</span>->sinter(<span class="string">"set"</span>,<span class="string">"set1"</span>,<span class="string">'set2'</span>);<span class="comment">//交集(所有集合都有的元素)</span></span><br><span class="line"><span class="variable">$res</span> = <span class="variable">$redis</span>->sinterstore(<span class="string">"inter"</span>,<span class="string">"set"</span>,<span class="string">"set1"</span>);<span class="comment">///取多个集合的交集,存在第三个集合里面</span></span><br><span class="line"><span class="variable">$redis</span>->sunion(<span class="string">"set"</span>,<span class="string">"set1"</span>,<span class="string">'set2'</span>);<span class="comment">//并集(所有集合合并去重的元素)</span></span><br><span class="line"><span class="variable">$redis</span>->sunionstore(<span class="string">"union"</span>,<span class="string">"set"</span>,<span class="string">"set1"</span>);<span class="comment">///取多个集合的并集,存在第三个集合里面</span></span><br><span class="line"><span class="variable">$redis</span>->smove(<span class="string">"set1"</span>,<span class="string">"set2"</span>,<span class="string">"value"</span>);<span class="comment">///第一个集合元素剪切到第二个集合里面。</span></span><br><span class="line"><span class="variable">$redis</span>->scard(<span class="string">"set"</span>);<span class="comment">//返回集合中元素的个数</span></span><br><span class="line"><span class="variable">$redis</span>->sismember(<span class="string">"set"</span>,<span class="string">"value"</span>);<span class="comment">//判断某个元素是否为集合的元素</span></span><br><span class="line"><span class="variable">$redis</span>->srandmember(<span class="string">"set"</span>);<span class="comment">//随机返回集合内的一个元素,不会删除元素</span></span><br><span class="line"></span><br><span class="line"><span class="variable">$redis</span>->keys(<span class="string">"*"</span>); <span class="comment">//返回所有key</span></span><br><span class="line"><span class="variable">$redis</span>->keys(<span class="string">"*t"</span>); <span class="comment">//返回所有s开头的key</span></span><br><span class="line"><span class="variable">$res</span> = <span class="variable">$redis</span>->keys(<span class="string">"*"</span>);</span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$res</span> <span class="keyword">as</span> <span class="variable">$k</span> => <span class="variable">$v</span>) {</span><br><span class="line"><span class="keyword">echo</span> <span class="variable">$v</span>.<span class="string">"=>"</span>.<span class="variable">$redis</span>->get(<span class="variable">$v</span>).<span class="string">"<br>"</span>;</span><br><span class="line">}</span><br><span class="line"><span class="variable">$redis</span>->exists(<span class="string">"set"</span>); <span class="comment">//判断该key是否存在</span></span><br><span class="line"><span class="variable">$redis</span>->del(<span class="string">"inter"</span>); <span class="comment">//删除该key</span></span><br><span class="line"><span class="variable">$redis</span>->expire(<span class="string">"set2"</span>,<span class="number">100</span>); <span class="comment">//设置key 过期时间10s</span></span><br><span class="line"><span class="variable">$redis</span>->ttl(<span class="string">"set3"</span>);<span class="comment">//查看过期剩余时间s</span></span><br><span class="line"></span><br><span class="line"><span class="variable">$redis</span>->select(<span class="string">"1"</span>);<span class="comment">// 选择数据库</span></span><br><span class="line"><span class="variable">$redis</span>->set(<span class="string">"name"</span>,<span class="string">"test"</span>);<span class="comment">// 设置key=>value</span></span><br><span class="line"><span class="variable">$redis</span>->get(<span class="string">"name"</span>);<span class="comment">// 根据key获取value</span></span><br><span class="line"><span class="variable">$redis</span>->move(<span class="string">"get"</span>,<span class="number">1</span>);<span class="comment">// 把key移到另一个数据库</span></span><br><span class="line"><span class="variable">$redis</span>->persist(<span class="string">"set2"</span>);<span class="comment">// 移除过期时间</span></span><br><span class="line"><span class="variable">$redis</span>->randomkey();<span class="comment">//随机返回一个key</span></span><br><span class="line"><span class="variable">$redis</span>->rename(<span class="string">"names"</span>,<span class="string">"newname"</span>);<span class="comment">//重命名key</span></span><br><span class="line"><span class="variable">$redis</span>->type(<span class="string">"zset"</span>);<span class="comment">//获取key类型</span></span><br><span class="line"><span class="variable">$redis</span>->dbsize();<span class="comment">//获取数据库key个数</span></span><br><span class="line"><span class="variable">$redis</span>->info();<span class="comment">//获取redis服务信息</span></span><br><span class="line"><span class="variable">$redis</span>->echo(<span class="string">"hello,world"</span>);<span class="comment">//输出函数</span></span><br><span class="line"><span class="comment">//******************************set集合**********************************************************</span></span><br><span class="line"><span class="comment">//redis有五大数据类型</span></span><br><span class="line"><span class="comment">//字符串 string</span></span><br><span class="line"><span class="comment">//hash 表</span></span><br><span class="line"><span class="comment">//链表结构 list</span></span><br><span class="line"><span class="comment">//set 集合(无序)</span></span><br><span class="line"><span class="comment">//zset 有序集合</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//string来存储用户的最大id,用来id的自增</span></span><br><span class="line"><span class="comment">//hash 表来存储用户的详细信息</span></span><br><span class="line"><span class="comment">//list链表结构来存储用户的id号</span></span><br><span class="line"><span class="variable">$uid</span> = <span class="variable">$redis</span>->incr(<span class="string">"blog:id"</span>); <span class="comment">//自增长</span></span><br><span class="line"><span class="variable">$res</span> = <span class="variable">$redis</span>->hmset(<span class="string">'blog:user:'</span> . <span class="variable">$uid</span>, <span class="keyword">array</span>(<span class="string">'id'</span> => <span class="variable">$uid</span>, <span class="string">'username'</span> =><span class="string">'admin'</span>.time() . time(), <span class="string">'password'</span> => md5(time()))); <span class="comment">//hash表插入一条记录</span></span><br><span class="line"><span class="variable">$redis</span>->rpush(<span class="string">"blog:uid"</span>, <span class="variable">$uid</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="variable">$res</span> = <span class="variable">$redis</span>->hgetall(<span class="string">"blog:user:"</span>.<span class="variable">$uid</span>);</span><br><span class="line"><span class="variable">$redis</span>->del(<span class="string">"blog:user:"</span>.<span class="variable">$uid</span>);<span class="comment">//删除用户</span></span><br><span class="line"><span class="variable">$redis</span>->lrem(<span class="string">"blog:uid"</span>,<span class="variable">$uid</span>);<span class="comment">//删除链表中的id</span></span><br><span class="line">print_R(<span class="variable">$res</span>);<span class="keyword">die</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="variable">$count</span> = <span class="variable">$redis</span>->lsize(<span class="string">"blog:uid"</span>); <span class="comment">//list类型count总数 </span></span><br><span class="line"><span class="variable">$page_size</span> = <span class="number">3</span>;</span><br><span class="line"><span class="variable">$page_num</span> = !<span class="keyword">empty</span>(<span class="variable">$_GET</span>[<span class="string">'page'</span>]) ? <span class="variable">$_GET</span>[<span class="string">'page'</span>] : <span class="number">1</span>;</span><br><span class="line"><span class="variable">$page_count</span> = ceil(<span class="variable">$count</span> / <span class="variable">$page_size</span>);</span><br><span class="line"><span class="variable">$ids</span> = <span class="variable">$redis</span>->lrange(<span class="string">"blog:uid"</span>, (<span class="variable">$page_num</span> - <span class="number">1</span>) * <span class="variable">$page_size</span>, ((<span class="variable">$page_num</span> - <span class="number">1</span>) * <span class="variable">$page_size</span> + <span class="variable">$page_size</span> - <span class="number">1</span>));</span><br><span class="line"></span><br><span class="line"><span class="keyword">foreach</span> (<span class="variable">$ids</span> <span class="keyword">as</span> <span class="variable">$v</span>) {</span><br><span class="line"><span class="variable">$ress</span>[] = <span class="variable">$redis</span>->hgetall(<span class="string">"blog:user:"</span> . <span class="variable">$v</span>); <span class="comment">//获取记录</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">echo</span><span class="string">"<pre>"</span>;</span><br><span class="line">print_r(<span class="variable">$ress</span>);</span><br></pre></td></tr></table></figure><p>原文链接:<br><a href="https://www.jianshu.com/p/c1c798828477" title="php操作redis笔记!">php操作redis笔记!</a></p>]]></content>
<summary type="html">
<p>这里主要是用的predis</p>
</summary>
<category term="PHP" scheme="https://hexo.lilis.xin/tags/PHP/"/>
<category term="redis" scheme="https://hexo.lilis.xin/tags/redis/"/>
</entry>
<entry>
<title>laravel-admin安装</title>
<link href="https://hexo.lilis.xin/posts/16eb654d/"/>
<id>https://hexo.lilis.xin/posts/16eb654d/</id>
<published>2018-09-10T04:13:57.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>1.5版本需要安装PHP 7+和Laravel 5.5</p><p>首先确保安装好了laravel,并且数据库连接设置正确。</p><a id="more"></a><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">composer <span class="keyword">require</span> encore/laravel-admin <span class="string">"1.5.*"</span></span><br></pre></td></tr></table></figure><p>然后运行下面的命令来发布资源:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php artisan vendor:publish --provider=<span class="string">"Encore\Admin\AdminServiceProvider"</span></span><br></pre></td></tr></table></figure><p>在该命令会生成配置文件config/admin.php,可以在里面修改安装的地址、数据库连接、以及表名,都可以用默认配置不修改。</p><p>然后运行下面的命令完成安装:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">php artisan admin:install</span><br></pre></td></tr></table></figure><p>启动服务后,在浏览器打开 <code>http://localhost/admin/</code> ,使用用户名 <code>admin</code> 和密码 <code>admin</code>登陆.<br>ps 如果报一下错误</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Specified key was too long error</span><br></pre></td></tr></table></figure><p>需要在<code>/app/Providers/AppServiceProvider.php</code>文件中修改</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">namespace</span> <span class="title">App</span>\<span class="title">Providers</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> <span class="title">Illuminate</span>\<span class="title">Support</span>\{</span><br><span class="line"> <span class="title">ServiceProvider</span>,</span><br><span class="line"> <span class="title">Facades</span>\<span class="title">Schema</span>};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AppServiceProvider</span> <span class="keyword">extends</span> <span class="title">ServiceProvider</span></span></span><br><span class="line"><span class="class"></span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">boot</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> Schema::defaultStringLength(<span class="number">191</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">function</span> <span class="title">register</span>(<span class="params"></span>)</span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="comment">//</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>1.5版本需要安装PHP 7+和Laravel 5.5</p>
<p>首先确保安装好了laravel,并且数据库连接设置正确。</p>
</summary>
<category term="PHP" scheme="https://hexo.lilis.xin/tags/PHP/"/>
<category term="laravel" scheme="https://hexo.lilis.xin/tags/laravel/"/>
<category term="laravel-admin" scheme="https://hexo.lilis.xin/tags/laravel-admin/"/>
</entry>
<entry>
<title>Hash索引和B-Tree索引</title>
<link href="https://hexo.lilis.xin/posts/294f33b7/"/>
<id>https://hexo.lilis.xin/posts/294f33b7/</id>
<published>2018-08-28T12:03:58.000Z</published>
<updated>2019-09-12T06:27:03.000Z</updated>
<content type="html"><![CDATA[<script src="/assets/js/APlayer.min.js"> </script><p>索引是帮助mysql获取数据的数据结构。最常见的索引是Btree索引和Hash索引。</p><p>不同的引擎对于索引有不同的支持:Innodb和MyISAM默认的索引是Btree索引;而Mermory默认的索引是Hash索引。</p><a id="more"></a><p>原文链接:<br><a href="https://blog.csdn.net/u014307117/article/details/47325091" title="Hash索引和BTree索引">Hash索引和BTree索引</a></p><h3 id="Hash索引"><a class="header-anchor" href="#Hash索引">➡️</a>Hash索引</h3><p>所谓Hash索引,当我们要给某张表某列增加索引时,将这张表的这一列进行哈希算法计算,得到哈希值,排序在哈希数组上。所以Hash索引可以一次定位,其效率很高,而Btree索引需要经过多次的磁盘IO,但是innodb和myisam之所以没有采用它,是因为它存在着好多缺点:<br>因为Hash索引比较的是经过Hash计算的值,所以只能进行等式比较,不能用于范围查询</p><ul><li>每次都要全表扫描</li><li>由于哈希值是按照顺序排列的,但是哈希值映射的真正数据在哈希表中就不一定按照顺序排列,所以无法利用Hash索引来加速任何排序操作</li><li>不能用部分索引键来搜索,因为组合索引在计算哈希值的时候是一起计算的。</li><li>当哈希值大量重复且数据量非常大时,其检索效率并没有Btree索引高的。</li></ul><h3 id="B-Tree索引"><a class="header-anchor" href="#B-Tree索引">➡️</a>B-Tree索引</h3><p>至于Btree索引,它是以B+树为存储结构实现的。</p><p>但是Btree索引的存储结构在Innodb和MyISAM中有很大区别。</p><p>在MyISAM中,我们如果要对某张表的某列建立Btree索引的话,如图:<br><img src="https://img-blog.csdn.net/20150806231335315"><br>所以我们经常会说MyISAM中数据文件和索引文件是分开的。</p><p>因此MyISAM的索引方式也称为非聚集,Innodb的索引方式成为聚集索引。</p><p>至于辅助索引,类似于主索引,唯一区别就是主索引上的值不能重复,而辅助索引可以重复。</p>]]></content>
<summary type="html">
<p>索引是帮助mysql获取数据的数据结构。最常见的索引是Btree索引和Hash索引。</p>
<p>不同的引擎对于索引有不同的支持:Innodb和MyISAM默认的索引是Btree索引;而Mermory默认的索引是Hash索引。</p>
</summary>
<category term="MySQL" scheme="https://hexo.lilis.xin/tags/MySQL/"/>
<category term="数据结构" scheme="https://hexo.lilis.xin/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
</entry>
</feed>