<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://wiki2.linuxformat.ru/skins/common/feed.css?97"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF141%3ACackePHP2</id>
		<title>LXF141:CackePHP2 - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF141%3ACackePHP2"/>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF141:CackePHP2&amp;action=history"/>
		<updated>2026-05-14T08:48:57Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.11.1</generator>

	<entry>
		<id>http://wiki2.linuxformat.ru/index.php?title=LXF141:CackePHP2&amp;diff=13857&amp;oldid=prev</id>
		<title>Crazy Rebel в 09:11, 16 мая 2012</title>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF141:CackePHP2&amp;diff=13857&amp;oldid=prev"/>
				<updated>2012-05-16T09:11:51Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;← Предыдущая&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Версия 09:11, 16 мая 2012&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Строка 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Строка 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;: '''Учебник ''CakePHP''' [[Категория:Учебники]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;: '''Учебник ''CakePHP''' [[Категория:Учебники]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;#160;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;{{Цикл/CakePHP}}&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;==''CakePHP'': Пи­шем за­груз­чик фай­лов==&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;==''CakePHP'': Пи­шем за­груз­чик фай­лов==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	<entry>
		<id>http://wiki2.linuxformat.ru/index.php?title=LXF141:CackePHP2&amp;diff=13715&amp;oldid=prev</id>
		<title>Crazy Rebel: викификация, оформление, иллюстрация</title>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF141:CackePHP2&amp;diff=13715&amp;oldid=prev"/>
				<updated>2012-04-21T05:32:57Z</updated>
		
		<summary type="html">&lt;p&gt;викификация, оформление, иллюстрация&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая статья&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: '''Учебник ''CakePHP''' [[Категория:Учебники]]&lt;br /&gt;
&lt;br /&gt;
==''CakePHP'': Пи­шем за­груз­чик фай­лов==&lt;br /&gt;
&lt;br /&gt;
: '''Часть II''' За­груз­чик фай­лов, что­бы де­лить­ся фай­ла­ми с кон­крет­ны­ми поль­зо­ва­те­ля­ми, а не со всем Ин­тер­не­том, пи­шет '''Грэм Уэл­дон'''.&lt;br /&gt;
&lt;br /&gt;
Ме­до­вый ме­сяц кон­чил­ся, крош­ка. Зай­мем­ся де­лом. Сле­дую­щая ите­ра­ция на­бе­га на ''CakePHP'' даст вам соб­ст­вен­ный за­груз­чик фай­лов. Он при­го­дит­ся, когда нуж­но от­пра­вить файл партнеру по бизнесу или кли­ен­ту или по­де­лить­ся им с дру­гом, тем не менее со­хранив кон­троль над досту­пом к вы­дан­но­му фай­лу. На­при­мер, пре­доста­вить кли­ен­ту файл ровно на неде­лю, при­чем доступ к фай­лу мож­но бу­дет в лю­бое вре­мя ото­брать. Вдо­ба­вок у нас по­лу­чит­ся бы­строе, лег­кое и рас­ши­-ряе­мое при­ло­жение.&lt;br /&gt;
&lt;br /&gt;
Нам нуж­на воз­мож­ность за­дать вла­дель­ца для ка­ж­до­го фай­ла, а так­же раз­де­лить этот файл с дру­ги­ми поль­зо­ва­те­ля­ми (доступ на чтение). По­это­му оп­ре­де­лим две раз­лич­ных свя­зи ме­ж­ду фай­лом и поль­зо­ва­те­лем. Пре­достав­ление фай­ла в доступ опи­шем свя­зью «Име­ет и при­над­ле­жит мно­гим», или, со­кра­щен­но, '''ИПM. ИПM''' ис­поль­зу­ет таб­ли­цу '''join''' для свя­зи двух за­пи­сей, и в ''CakePHP'' есть стан­дарт­ное со­гла­шение, ко­то­ро­му мы бу­дем сле­до­вать, что­бы кар­кас сде­лал за нас всю гряз­ную ра­бо­ту (со­от­вет­ст­вую­щий код мож­но най­ти на '''LXFDVD''').&lt;br /&gt;
&lt;br /&gt;
В упо­мя­ну­той таб­ли­це '''join''' за­да­ют­ся поль­зо­ва­те­ли, ко­то­рым раз­ре­шен дос­туп к за­дан­ным фай­лам. Со­глас­но стан­дар­ту, имя таб­ли­цы '''join''', ис­поль­зуе­мой для свя­зи '''ИПM''', долж­но со­сто­ять из имен свя­зы­вае­мых таб­лиц в ал­фа­вит­ном по­ряд­ке, со­еди­нен­ных сим­во­лом под­чер­ки­ва­ния:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 CREATE TABLE `uploads_users` (&lt;br /&gt;
 `id` CHAR(36) NOT NULL PRIMARY KEY,&lt;br /&gt;
 `upload_id` CHAR(36) NOT NULL,&lt;br /&gt;
 `user_id` CHAR(36) NOT NULL&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Соз­дай­те свои таб­ли­цы в но­вой ба­зе дан­ных, и зай­мем­ся вы­печ­кой и за­пус­ком про­ек­та.&lt;br /&gt;
&lt;br /&gt;
===На старт… вни­ма­ние… пе­чем!===&lt;br /&gt;
&lt;br /&gt;
''Bake'' – спе­ци­аль­ная ути­ли­та, по­став­ляе­мая с ''CakePHP'' и за­пус­кае­мая из кон­со­ли. Что­бы ра­бо­тать с ней бы­ло удоб­нее, путь '''cake/console''' внут­ри ''CakePHP'' сле­ду­ет вклю­чить в пе­ре­мен­ную ок­ру­же­ния '''PATH'''. Для это­го (как го­во­ри­лось на пре­ды­ду­щем уро­ке) вы­пол­ни­те сле­дую­щую ко­ман­ду в кон­со­ли:&lt;br /&gt;
&lt;br /&gt;
 $ export PATH=”$PATH:/path/to/cakephp/cake/console”&lt;br /&gt;
&lt;br /&gt;
И, ко­неч­но, ''PHP'' дол­жен быть дос­ту­пен в ко­манд­ной стро­ке (обыч­но это дос­ти­га­ет­ся ус­та­нов­кой па­ке­та ''php-cli'' или по­доб­но­го).&lt;br /&gt;
&lt;br /&gt;
Что­бы соз­дать ске­лет про­ек­та, в кон­со­ли ско­ман­дуй­те:&lt;br /&gt;
&lt;br /&gt;
 $ cake bake project fileshare&lt;br /&gt;
 $ cd fileshare&lt;br /&gt;
&lt;br /&gt;
За­тем на­строй­те со­еди­не­ние с ба­зой дан­ных. Из­ме­ни­те па­ра­мет­ры, при­ве­ден­ные в '''Лис­тин­ге 2''' в фай­ле '''config/database.php''', на под­хо­дя­щие для ва­шей ба­зы дан­ных. Дос­та­точ­но за­дать со­еди­не­ние '''“default”'''.&lt;br /&gt;
&lt;br /&gt;
И по­ка мы за­ни­ма­ем­ся вы­печ­кой, взва­лив всю чер­ную ра­бо­ту на ''CakePHP'', за­од­но вы­пе­чем кон­трол­ле­ры, мо­де­ли и пред­став­ле­ния, соз­дав ос­но­ву на­ше­го про­ек­та.&lt;br /&gt;
&lt;br /&gt;
 $ cake bake all user&lt;br /&gt;
 $ cake bake all upload&lt;br /&gt;
&lt;br /&gt;
Те­перь у нас есть го­то­вый к ис­поль­зо­ванию сайт, ко­то­рый свя­зы­ва­ет поль­зо­ва­те­лей с за­гру­жен­ны­ми фай­ла­ми и по­зво­ля­ет нам за­полнить ба­зу дан­ных удоб­ным спо­со­бом. Но по­ка фай­лы за­гру­жать ра­новато: следует пе­ре­де­лать то, что при­пас нам ''CakePHP'', до­ба­вив функ­цио­нал по за­груз­ке фай­лов и пре­д­от­вра­тив до­бав­ление и из­менение ин­фор­ма­ции о поль­зо­ва­те­лях по­сто­ронними. По­вы­сим так­же безо­пас­ность все­го при­ло­жения, по­за­бо­тив­шись, что­бы толь­ко за­ре­ги­ст­ри­ро­ван­ные поль­зо­ва­те­ли име­ли возможность модифици­ровать дан­ные.&lt;br /&gt;
&lt;br /&gt;
===За­пре­мся из­нут­ри===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Заголовок=Клас­со­вая борь­ба|Содержание=В ''PHP'' у нас нет про­странств имен, и клас­сам нель­зя да­вать име­на, уже ис­поль­зо­ван­ные в ''CakePHP''. В ''CakePHP'' есть класс '''File''', и мы не мог­ли дать имя '''“File”''' на­шей мо­де­ли в при­ме­ре – это при­ве­ло бы к кон­флик­ту клас­сов. Вме­сто не­го мы вос­поль­зо­ва­лись име­нем '''“Upload”'''. Спи­сок всех клас­сов ''CakePHP'' см. в от­кры­том API: http://api.cakephp.org.|Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
У нас есть таб­ли­ца '''“users”''', и уже ра­бо­та­ет до­бав­ление поль­зо­ва­те­ля – об этом по­за­бо­тил­ся ''CakePHP''; от­крой­те при­ло­жение в брау­зе­ре, до­ба­вив к ад­ре­су '''users'''. На­при­мер, http://localhost/fileshare/users. Итак, что же де­лать даль­ше? Ха, па­ро­ли хра­нят­ся в от­кры­том ви­де; и нас как-то не про­сят вво­дить ло­гин и па­роль. От­крой­те файл '''app_controller.php''' в корне про­ек­та. Это пустой кон­трол­лер, от ко­то­ро­го на­сле­ду­ют функ­цио­нал все осталь­ные кон­трол­ле­ры при­ло­жения. Все, что мы сде­ла­ем здесь, бу­дет доступ­но во всех кон­трол­ле­рах, так что это пре­вос­ход­ное ме­сто, что­бы за­ста­вить поль­зо­ва­те­лей вво­дить ло­гин и па­роль. До­бавь­те ком­по­нен­ты '''Auth''' и '''Session'''. Те­перь ваш '''AppController''' бу­дет вы­гля­деть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 class AppController extends Controller {&lt;br /&gt;
 var $components = array(‘Auth’, ‘Session’);&lt;br /&gt;
 }&lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
По­про­бо­вав об­но­вить спи­сок '''users''', вы по­лу­чи­те со­об­ще­ние об ошиб­ке, сиг­на­ли­зи­рую­щее о том, что дей­ст­вия '''login''' не су­ще­ст­ву­ет. Ес­ли по­смот­ри­те пов­ни­ма­тель­нее, то уви­ди­те, что URL то­же из­ме­нил­ся на '''/users/login'''. К сча­стью, всю са­мую труд­ную ра­бо­ту за нас уже сде­лал ''CakePHP'', и нам ос­та­лось соз­дать дей­ст­вие (функ­цию) в кон­тол­ле­ре и фор­му для вхо­да в сис­те­му. От­крой­те '''controllers/users_controller.php''' и до­бавь­те ту­да дей­ст­вие '''login''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 function login() {&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ошиб­ки тут нет – функ­ция пус­та, и это все, что нам нуж­но для ау­тен­ти­фи­ка­ции в кон­трол­ле­ре.&lt;br /&gt;
&lt;br /&gt;
Что­бы не пе­ре­хит­рить са­мих се­бя, убе­дим­ся, что мы мо­жем за­ре­ги­ст­ри­ро­вать поль­зо­ва­те­ля, ес­ли это еще не сде­ла­но. Мы поч­ти по­кон­чи­ли с ау­тен­ти­фи­ка­ци­ей поль­зо­ва­те­ля, и весь функ­цио­нал стал бы нам не­дос­ту­пен – не сде­лав ис­клю­че­ние для стра­ни­цы ре­ги­ст­ра­ции, мы не смог­ли бы вой­ти в на­шу кле­вую сис­те­му. Соз­дай­те ме­тод '''beforeFilter''' в кон­трол­ле­ре users и до­бавь­те ту­да код, пре­ду­пре­ж­даю­щий ком­по­нент '''Auth''', что мы мо­жем за­хо­дить на стра­ни­цу ре­ги­ст­ра­ции, да­же если еще не во­шли в сис­те­му:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 function beforeFilter() {&lt;br /&gt;
 $this-&amp;gt;Auth-&amp;gt;allow(‘add’);&lt;br /&gt;
 return parent::beforeFilter();&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Соз­дай­те пред­став­ле­ние '''login''' в но­вом фай­ле '''views/users/login.ctp''', как опи­са­но в '''Лис­тин­ге 3 LXFDVD'''.&lt;br /&gt;
&lt;br /&gt;
Об­но­ви­те стра­ни­цу с со­об­ще­ни­ем об ошиб­ке, и пе­редва­ми поя­вит­ся фор­ма для вхо­да в сис­те­му. Об­ра­ти­те вни­ма­ние, что вы смо­же­те зай­ти на стра­ни­цу '''/users/add''', но все ос­таль­ные ссыл­ки бу­дут пе­ре­на­прав­лять­ся на стра­ни­цу '''/users/login'''. За­ре­ги­ст­ри­руй­те се­бя как поль­зо­ва­те­ля – это при­го­дит­ся для тес­ти­ро­ва­ния при­ло­же­ния. Про­верь­те со­дер­жи­мое ба­зы дан­ных. Вы уви­ди­те, что па­роль ав­то­ма­ти­че­ски пре­вра­тил­ся в хэш. Чу­дес­но! Так­же сто­ит уда­лить не­ко­то­рые из ав­то­ма­ти­че­ски сге­не­ри­ро­ван­ных по­лей и по­лей вво­да, ко­то­ры­ми мы не бу­дем поль­зо­вать­ся, что­бы у поль­зо­ва­те­лей был дос­туп толь­ко к раз­ре­шен­ным по­лям. Итак, уда­ли­те сле­дую­щее по­ле из пред­став­ле­ний '''add''' и '''edit''' в фай­лах '''views/users/add.ctp''' и '''views/users/edit.ctp''':&lt;br /&gt;
&lt;br /&gt;
 echo $this-&amp;gt;Form-&amp;gt;input(‘Upload’);&lt;br /&gt;
&lt;br /&gt;
===За­гру­жа­ем фай­лы===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF141_69_1.jpg|300px]] Ин­декс users дос­ту­пен, ес­ли до­бав­ле­на ау­тен­ти­фи­ка­ция.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
По­ра соз­дать дей­ст­вие для за­груз­ки фай­лов. Сна­ча­ла соз­да­дим под­ка­та­лог uploads в ка­та­ло­ге про­ек­та, где бу­дут хра­нить­ся за­гру­жен­ные фай­лы, и сде­ла­ем его вла­дель­цем поль­зо­ва­те­ля, от име­ни ко­то­ро­го за­пус­ка­ет­ся web-сер­вер. В од­них ди­ст­ри­бу­ти­вах это '''www-data''', в дру­гих – '''apache''' или '''www'''. Ука­жи­те поль­зо­ва­те­ля для сво­ей сис­те­мы.&lt;br /&gt;
&lt;br /&gt;
 $ mkdir uploads&lt;br /&gt;
 $ chown www-data uploads&lt;br /&gt;
&lt;br /&gt;
А не по­напи­сать ли нам код? Начнем с из­менения страницы за­груз­ки фай­лов, что­бы фай­лы мож­но бы­ло за­гру­жать и безо­пас­но со­хра­нять. ''Bake'' стря­па­ет неплохую фор­му, но мы уда­лим из нее несколь­ко ав­то­ма­ти­че­­ски сгенери­ро­ван­ных по­лей и за­меним их по­лем за­груз­ки фай­ла. Столб­цы, ко­то­рые мы оп­ре­де­ли­ли в ба­зе дан­ных, пред­ва­ри­тель­но за­пол­ня­ют­ся ав­то­ма­ти­че­­ски. По­сле за­груз­ки фай­ла мы по­лу­чим всю необ­хо­ди­мую ин­фор­ма­цию о нем. Уда­ли­те по­ля вво­да '''filename, filesize''' и '''filemime''' из пред­став­ления за­груз­ки фай­лов в фай­ле '''views/uploads/add.ctp''' и до­бавь­те по­ле вво­да '''file'''. Мы не соз­да­ли стол­бец '''file''' в ба­зе дан­ных, по­это­му ''CakePHP'' не сде­ла­ет чер­но­вую ра­бо­ту для это­го по­ля, и нуж­но так­же ука­зать, ка­ко­го ти­па долж­но быть по­ле, что­бы оно соз­да­лось пра­виль­но. Сде­ла­ем и еще од­но неболь­шое из­менение – уда­лим по­ле вво­да '''user_id''', соз­дан­ное для нас ''CakePHP''. Вме­сто не­го до­ба­вим в кон­трол­лер код, ав­то­ма­ти­че­ски свя­зы­ваю­щий фай­лы с поль­зо­ва­те­лем, ко­то­рый в дан­ный мо­мент во­шел в сис­те­му. По­смотрим, как те­перь вы­гля­дят поля вво­да на фор­ме. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 &amp;lt;?php echo $this-&amp;gt;Form-&amp;gt;create(‘Upload’, array(‘type’ =&amp;gt; ‘file’));?&amp;gt;&lt;br /&gt;
 &amp;lt;fieldset&amp;gt;&lt;br /&gt;
 &amp;lt;legend&amp;gt;&amp;lt;?php __(‘Add Upload’); ?&amp;gt;&amp;lt;/legend&amp;gt;&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
 echo $this-&amp;gt;Form-&amp;gt;input(‘title’);&lt;br /&gt;
 echo $this-&amp;gt;Form-&amp;gt;input(‘description’);&lt;br /&gt;
 echo $this-&amp;gt;Form-&amp;gt;input(‘file’, array(‘type’ =&amp;gt; ‘file’));&lt;br /&gt;
 echo $this-&amp;gt;Form-&amp;gt;input(‘User’);&lt;br /&gt;
 ?&amp;gt;&lt;br /&gt;
 &amp;lt;/fieldset&amp;gt;&lt;br /&gt;
 &amp;lt;?php echo $this-&amp;gt;Form-&amp;gt;end(__(‘Submit’, true));?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Об­ра­бот­ка за­гру­жен­но­го фай­ла===&lt;br /&gt;
&lt;br /&gt;
Конеч­но, файл у нас есть, но нуж­но еще и об­ра­бо­тать его долж­ным об­ра­зом, что­бы вы­дать со­об­щение о ошиб­ке, ес­ли файл за­гру­жен некор­рект­но, ли­бо со­хранить его в на­шем ка­та­ло­ге '''uploads''', ес­ли он за­гру­жен кор­рект­но. Для это­го от­кро­ем файл '''controllers/uploads_controller.php''' в соз­дан­ном про­ек­те и из­меним функ­цию '''add()''': пусть об­ра­ба­ты­ва­ет файл, ес­ли он есть. В треть­ей стро­ке этой функ­ции про­ис­хо­дит со­хранение дан­ных мо­де­ли. Из­мените опе­ра­тор усло­вия так, что­бы в нем вы­зы­ва­лась функ­ция '''uploadFile()''', ко­то­рую мы на­пи­шем чуть поз­же:&lt;br /&gt;
&lt;br /&gt;
 if ($this-&amp;gt;uploadFile() &amp;amp;&amp;amp; $this-&amp;gt;Upload-&amp;gt;save($this-&amp;gt;data)) {&lt;br /&gt;
&lt;br /&gt;
Про­сто, не прав­да ли? Те­перь соз­да­дим в том же кон­трол­ле­ре функ­цию '''uploadFile()''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 function uploadFile() {&lt;br /&gt;
 $file = $this-&amp;gt;data[‘Upload’][‘file’];&lt;br /&gt;
 if ($file[‘error’] === UPLOAD_ERR_OK) {&lt;br /&gt;
 $id = String::uuid();&lt;br /&gt;
 if (move_uploaded_file($file[‘tmp_name’], APP.’uploads’.&lt;br /&gt;
 DS.$id)) {&lt;br /&gt;
 $this-&amp;gt;data[‘Upload’][‘id’] = $id;&lt;br /&gt;
 $this-&amp;gt;data[‘Upload’][‘user_id’] = $this-&amp;gt;Auth-&amp;gt;user(‘id’);&lt;br /&gt;
 $this-&amp;gt;data[‘Upload’][‘filename’] = $file[‘name’];&lt;br /&gt;
 $this-&amp;gt;data[‘Upload’][‘filesize’] = $file[‘size’];&lt;br /&gt;
 $this-&amp;gt;data[‘Upload’][‘filemime’] = $file[‘type’];&lt;br /&gt;
 return true;&lt;br /&gt;
 }&lt;br /&gt;
 }&lt;br /&gt;
 return false;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Опять же, все про­сто. Мы за­гру­жа­ем файл, и ес­ли мы мо­жем пе­ре­мес­тить его в нуж­ный ка­та­лог, воз­вра­ща­ем '''true'''. В про­цес­се это­го мы вруч­ную генери­ру­ем иден­ти­фи­ка­тор, ко­то­рый станет безо­пас­ным именем со­хра­няе­мо­го фай­ла. Это ис­клю­чит непри­ят­но­сти от поль­зо­ва­те­лей, за­гру­жаю­щих фай­лы со стран­ны­ми и по­тен­ци­аль­но опас­ны­ми для сис­те­мы име­на­ми, ко­то­рые в про­тив­ном слу­чае уго­дят пря­мо в ва­шу фай­ло­вую сис­те­му. Руч­ная генера­ция UUID с по­мо­щью ме­то­да '''String::uuid()''' уст­ра­ня­ет эту ды­ру в безо­пас­но­сти и га­ран­ти­ру­ет безо­пас­ную за­груз­ку фай­ла, а ис­ход­ное имя фай­ла хранит­ся в ба­зе дан­ных и от­прав­ля­ет­ся поль­зо­ва­те­лю при ска­чи­вании.&lt;br /&gt;
&lt;br /&gt;
Зай­мем­ся же ска­чи­ванием. Но пре­ж­де чем от­вле­кать­ся на это, по­про­буй­те до­ба­вить па­ру фай­лов. Вы уви­ди­те, что они успеш­но по­па­да­ют в ба­зу дан­ных; а в соз­дан­ном на­ми ка­та­лог '''uploads''' по­яв­ля­ют­ся фай­лы с со­от­вет­ст­вую­щи­ми име­нам иден­ти­фи­ка­то­ра­ми. Ес­ли на дан­ном эта­пе у вас возник­нут про­бле­мы, убе­ди­тесь, что у web-сер­ве­ра есть пра­ва на запись в ка­та­лог '''uploads'''.&lt;br /&gt;
&lt;br /&gt;
Еще од­на кру­тая вещь, ко­то­рую мы здесь сде­ла­ем – свя­жем поль­зо­ва­те­ля с '''$this-&amp;gt;Auth-&amp;gt;user(‘id’)''': это иден­ти­фи­ка­тор поль­зо­ва­те­ля, во­шед­ше­го в дан­ный мо­мент в сис­те­му. Так как ранее мы по­за­бо­ти­лись о безо­пас­но­сти, то зна­ем, что поль­зо­ва­тель дол­жен за­ре­ги­ст­ри­ро­вать­ся, что­бы от­крыть эту страницу, по­это­му его иден­ти­фи­ка­тор не мо­жет быть пустым и всегда кор­рек­тен.&lt;br /&gt;
&lt;br /&gt;
===Уда­ля­ем свя­зи===&lt;br /&gt;
&lt;br /&gt;
Вы за­ме­ти­те, что мы про­дуб­ли­ро­ва­ли свя­зи для мо­де­лей '''User''' и '''Upload'''. Возь­мем, на­при­мер, мо­дель '''User''' в фай­ле '''models/user.php'''; ''CakePHP'' соз­дал свя­зи '''hasMany''' и '''hasAndBelongsToMany''', обе с ин­дек­сом '''Upload'''. Ра­бо­тать это не бу­дет: кон­фликт имен при­ве­дет к то­му, что в пред­став­ле­ни­ях ото­бра­зят­ся не­вер­ные дан­ные. Из­ме­ни­те связь '''hasAndBelongsToMany''' в мо­де­ли '''User''' на '''Shared­Upload'''. Ана­ло­гич­но, в мо­де­ли '''Upload''' в фай­ле '''models/upload.php''' из­ме­ни­те связь '''ИПМ''' на '''SharedUser''':&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF141_70_1.jpg|300px]] Реа­ли­зо­вать за­груз­ку фай­лов про­сто.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 // User Model&lt;br /&gt;
 var $hasAndBelongsToMany = array(&lt;br /&gt;
 ‘SharedUpload’ =&amp;gt; array(&lt;br /&gt;
 ‘className’ =&amp;gt; ‘Upload’,&lt;br /&gt;
 ...&lt;br /&gt;
 // Upload Model&lt;br /&gt;
 var $hasAndBelongsToMany = array(&lt;br /&gt;
 ‘SharedUser’ =&amp;gt; array(&lt;br /&gt;
 ‘className’ =&amp;gt; ‘User’,&lt;br /&gt;
 ..&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Что­бы эти из­ме­не­ния свя­зей кор­рект­но об­ра­бо­та­лись в пред­став­ле­ни­ях, из­ме­ни­те ин­декс, на ко­то­рый ссы­ла­ют­ся пред­став­ле­ния в раз­де­ле '''related''' в ниж­ней час­ти ин­дек­сов '''view'''. В фай­ле '''views/users/view.ctp''' из­ме­ни­те две стро­ки&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 &amp;lt;?php if (!empty($user[‘pload’])):?&amp;gt;&lt;br /&gt;
 foreach ($user[‘Upload’] as $upload):&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
на сле­дую­щие:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 &amp;lt;?php if (!empty($user[‘SharedUpload’])):?&amp;gt;&lt;br /&gt;
 foreach ($user[‘SharedUpload’] as $upload):&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Итак, вы мо­же­те ре­ги­ст­ри­ро­вать но­вых поль­зо­ва­те­лей, за­хо­дить в сис­те­му, за­гру­жать фай­лы и свя­зы­вать их с поль­зо­ва­те­ля­ми. С миниму­мом на­пи­сан­но­го ко­да и за­тра­чен­ных уси­лий нам уда­лось достичь непло­хой функ­цио­наль­но­сти. Хо­ро­шень­ко про­тес­ти­руй­те сис­те­му, пре­ж­де чем пе­ре­хо­дить к сле­дую­ще­му эта­пу.&lt;br /&gt;
&lt;br /&gt;
===Про­смотр и ска­чи­вание фай­лов===&lt;br /&gt;
&lt;br /&gt;
Ес­ли вы уже по­иг­ра­ли с на­ви­га­ци­ей по имею­щим­ся пред­став­лениям, вам по­па­да­лась страница пред­став­ления для од­но­го из за­гру­жен­ных фай­лов. На ней по­ка­за­ны все ме­та­дан­ные фай­ла, но сам файл ска­чать по­ка нель­зя. Да­вай­те из­меним кое-что так, что­бы поя­ви­лась воз­мож­ность ска­чи­вания фай­лов, и у нас поя­вил­ся доступ к ним. Пер­вым де­лом до­бавь­те ссыл­ку в файл пред­став­ления '''views/uploads/view.ctp''', в лю­бом мес­те (я ре­шил до­ба­вить ее в са­мый низ):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 &amp;lt;dt&amp;lt;?php if ($i % 2 == 0) echo $class;?&amp;gt;&amp;gt;&amp;lt;?php __(‘Download’);?&amp;gt;&amp;lt;/dt&amp;gt;&lt;br /&gt;
 &amp;lt;dd&amp;lt;?php if ($i++ % 2 == 0) echo $class;?&amp;gt;&amp;gt;&lt;br /&gt;
 &amp;lt;?php echo $this-&amp;gt;Html-&amp;gt;link(__(‘Download’, true),&lt;br /&gt;
 array(‘action’ =&amp;gt; ‘download’, $upload[‘Upload’][‘id’])); &lt;br /&gt;
 ?&amp;gt;&amp;amp;nbsp;&lt;br /&gt;
 &amp;lt;/dd&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
С этой ссыл­кой по­ра сно­ва принять­ся за дело и соз­дать дей­ст­вие для кон­трол­ле­ра: пускай оно об­ра­ба­ты­вает ска­чи­вание фай­ла. От­крой­те '''UploadsController''' в фай­ле '''controllers/uploads_controller.php''' сно­ва и до­бавь­те функ­цию ска­чи­вания. Она иниции­ру­ет ска­чи­вание и воз­вра­ща­ет поль­зо­ва­те­лю файл с ис­ход­ным именем, под ко­то­рым он был за­гру­жен. Код этой функ­ции слиш­ком ве­лик, что­бы по­ме­щать его здесь, и вы най­де­те его на на­шем DVD в '''Лис­тин­ге 4'''.&lt;br /&gt;
&lt;br /&gt;
Те­перь щелкните по этой ссыл­ке, и файл начнет за­гру­жать­ся че­рез ваш брау­зер! В этой функ­ции нуж­но кое-что до­де­лать, но по­верь­те, ''CakePHP'' уже сде­лал мно­го боль­ше. Сна­ча­ла про­ве­рим, есть ли иден­ти­фи­ка­тор. За­тем по­пы­та­ем­ся най­ти в ба­зе дан­ных запись о за­груз­ке фай­ла с та­ким иден­ти­фи­ка­то­ром, и по­ка мы там, про­ве­рим, что за­груз­ка свя­за­на с поль­зо­ва­те­лем, ко­то­рый в дан­ный мо­мент в сис­те­ме, или что файл был из­на­чаль­но за­гру­жен дан­ным поль­зо­ва­те­лем. И в том, и в дру­гом слу­чае доступ раз­ре­шен. Ес­ли за­про­сы не да­ют ре­зуль­та­та, зна­чит поль­зо­ва­тель пы­та­ет­ся по­лу­чить файл, к ко­то­ро­му у него нет досту­па, и мы пе­ре­на­пра­вим его к спи­ску фай­лов.&lt;br /&gt;
&lt;br /&gt;
===По­ка­жем лишь то, что мож­но===&lt;br /&gt;
&lt;br /&gt;
Что­бы спи­сок фай­лов имел смысл для всех поль­зо­ва­те­лей, нуж­но так­же из­менить дей­ст­вие '''index()''' в кон­трол­ле­ре '''Uploads''', что­бы вы­пол­нять ана­ло­гич­ную фильт­ра­цию и по­ка­зы­вать в спи­ске толь­ко те фай­лы, к ко­то­рым у поль­зо­ва­те­лей есть пра­ва досту­па, ина­че в нем бу­дет мас­са фай­лов, о ко­то­рых им знать из­лиш­не! Из­ме­ни­те дей­ст­вие '''index''' та­ким об­ра­зом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 function index() {&lt;br /&gt;
 $this-&amp;gt;Upload-&amp;gt;bindModel(array(‘hasOne’ =&amp;gt;&lt;br /&gt;
 array(‘UploadsUser’)), false);&lt;br /&gt;
 $this-&amp;gt;paginate = array(&lt;br /&gt;
 ‘conditions’ =&amp;gt; array(&lt;br /&gt;
 ‘OR’ =&amp;gt; array(&lt;br /&gt;
 ‘UploadsUser.user_id’ =&amp;gt; $this-&amp;gt;Auth-&amp;gt;user(‘id’),&lt;br /&gt;
 ‘Upload.user_id’ =&amp;gt; $this-&amp;gt;Auth-&amp;gt;user(‘id’),&lt;br /&gt;
 ),&lt;br /&gt;
 )&lt;br /&gt;
 );&lt;br /&gt;
 $this-&amp;gt;set(‘uploads’, $this-&amp;gt;paginate());&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На этот раз нам при­шлось до­ба­вить па­ра­метр '''false''' к вы­зо­ву '''bindModel()''', что­бы га­ран­ти­ро­вать кор­рект­ное раз­биение на стра­ницы. Функ­ция раз­биения на страницы принима­ет два от­дель­ных ре­зуль­та­та из ба­зы дан­ных. Пер­вый оп­ре­де­ля­ет чис­ло эле­мен­тов в таб­ли­це, со­от­вет­ст­ву­щих за­про­су, а вто­рой фак­ти­че­­ски воз­вра­ща­ет дан­ные. Па­ра­метр '''false''' ве­лит ''CakePHP'' удер­жать свя­зы­вание в пре­де­лах од­но­го за­про­са. Про­стое пра­ви­ло: ес­ли вы поль­зуе­тесь ме­то­дом '''bindModel''' и раз­бив­кой на страницы, в конец ме­то­да до­бавь­те '''false'''.&lt;br /&gt;
&lt;br /&gt;
Дей­ст­вие '''view()''' от по­доб­ной фильт­ра­ции то­же вы­иг­ры­ва­ет:&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF141_71_1.jpg|300px]] С по­мо­щью до­пол­ни­тель­ной ссыл­ки мож­но ска­чи­вать фай­лы, ко­то­рые бы­ли за­гру­же­ны.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 function view($id = null) {&lt;br /&gt;
 if (!$id) {&lt;br /&gt;
 $this-&amp;gt;Session-&amp;gt;setFlash(__(‘Invalid upload’, true));&lt;br /&gt;
 $this-&amp;gt;redirect(array(‘action’ =&amp;gt; ‘index’));&lt;br /&gt;
 }&lt;br /&gt;
 $this-&amp;gt;Upload-&amp;gt;bindModel(array(‘hasOne’ =&amp;gt;&lt;br /&gt;
 array(‘UploadsUser’)));&lt;br /&gt;
 $upload = $this-&amp;gt;Upload-&amp;gt;find(‘first’, array(&lt;br /&gt;
 ‘conditions’ =&amp;gt; array(&lt;br /&gt;
 ‘Upload.id’ =&amp;gt; $id,&lt;br /&gt;
 ‘OR’ =&amp;gt; array(&lt;br /&gt;
 ‘UploadsUser.user_id’ =&amp;gt; $this-&amp;gt;Auth-&amp;gt;user(‘id’),&lt;br /&gt;
 ‘Upload.user_id’ =&amp;gt; $this-&amp;gt;Auth-&amp;gt;user(‘id’),&lt;br /&gt;
 ),&lt;br /&gt;
 )&lt;br /&gt;
 ));&lt;br /&gt;
 if (!$upload) {&lt;br /&gt;
 $this-&amp;gt;Session-&amp;gt;setFlash(__(‘Invalid upload’, true));&lt;br /&gt;
 $this-&amp;gt;redirect(array(‘action’ =&amp;gt; ‘index’));&lt;br /&gt;
 }&lt;br /&gt;
 $this-&amp;gt;set(‘upload’, $upload);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===За­круг­ля­ем­ся===&lt;br /&gt;
&lt;br /&gt;
По­след­нее ук­ра­ше­ние, не­об­хо­ди­мое для при­ве­де­ния сай­та в бое­вую го­тов­ность – функ­ция '''logout'''. И я ве­ли­ко­душ­но дам вам код, ко­то­рый на­до по­мес­тить в '''UsersController''', что­бы мож­но бы­ло вы­хо­дить из сис­те­мы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
 public function logout() {&lt;br /&gt;
 $this-&amp;gt;redirect($this-&amp;gt;Auth-&amp;gt;logout());&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пред­став­ления не нуж­но, и пе­ре­на­прав­ление про­из­во­дит­ся, как толь­ко поль­зо­ва­тель от­кры­ва­ет URL '''/users/logout''' по­сле унич­то­жения сес­сии и вы­хо­да поль­зо­ва­те­ля из сис­те­мы.&lt;br /&gt;
&lt;br /&gt;
Итак, мы соз­да­ли за­щи­щен­ное мно­го­поль­зо­ва­тель­ское при­ло­жение для за­груз­ки и раз­де­ления фай­лов за ка­ких-то 20 ми­нут. Те­перь мож­но до­ба­вить до­полнитель­ный функ­цио­нал – на­при­мер, миниа­тю­ры для про­смот­ра за­гру­жен­но­го поль­зо­ва­те­ля­ми со­дер­жи­мо­го, или из­менить ме­ханизм раз­де­ления фай­лов, что­бы вы­би­рать поль­зо­ва­те­лей, не по­ка­зы­вая всем их пол­ный спи­сок.&lt;br /&gt;
&lt;br /&gt;
Так­же мож­но по­сы­лать поль­зо­ва­те­лям из­ве­щения по элек­трон­ной поч­те, что вы раз­де­ли­ли с ними фай­лы. На­де­юсь, вам по­нра­вил­ся этот урок, и созданный код при­го­дит­ся вам как учеб­ный при­мер или даже как го­то­вое ре­ше­ние для раз­де­ле­ния фай­лов с кли­ен­та­ми.&lt;br /&gt;
&lt;br /&gt;
===Ис­ход­ные ко­ды уро­ка===&lt;br /&gt;
&lt;br /&gt;
Ко­ды для на­ше­го трой­но­го уро­ка дос­туп­ны на '''GitHub''' под мо­ей учет­ной за­пи­сью http://github.com/predominant/cakephp_linux_format. Мо­же­те взять код от­ту­да, ес­ли не по­лу­ча­ет­ся сге­не­ри­ро­вать его ути­ли­той ''bake'' или вы про­сто хо­ти­те со­брать и за­пус­тить при­ло­же­ние по­бы­ст­рее – код мож­но ско­пи­ро­вать, опус­тив все эта­пы уро­ка.&lt;/div&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	</feed>