Define el uso de multipart como te dice Jack, pero primero debes de tener eso segundo debes de enviar por submit, he usado anteriormente el uso de CUploadFile que en la misma es como usar $_FILES dentro de PHP puro, es la parte que contiene nuestras variables temporales yo no tenia entendido mejor dicho no tenia el conocimiento de que existe una variable temporal que te asigne eso…, segunda si vas a definir una variable en tus rules dentro de tu model, y no la tienes en tu tabla donde necesitas adjuntar define esa variable temporal si es que lo quieres hacer de esta manera para eso define una propiedad en tu archivo model, eh indica el tamaño de esa propiedad que le desees dar osea si tu quieres indicar un tamaño maximo de archivos:
//mi propiedad se llama archivo
public $archivo;
array('archivo', 'FileValidator','types'=>'doc, docx, pdf, jpg','maxSize'=>10485760),
//Fijate que le defino que tipo de archivos le permito subir y ahi pongo el tamaño ahora analiza uqe estoy usando la libreria FileValidator este es un archivo que descargue no me acuerdo bien de que parte de yii.
//Código del archivo FileValidator
class FileValidator extends CFileValidator
{
/**
* Internally validates a file object.
* @param CModel $object the object being validated
* @param string $attribute the attribute being validated
* @param CUploadedFile $file uploaded file passed to check against a set of rules
*/
protected function validateFile($object, $attribute, $file)
{
if(null===$file || ($error=$file->getError())==UPLOAD_ERR_NO_FILE)
return $this->emptyAttribute($object, $attribute);
else if($error==UPLOAD_ERR_INI_SIZE || $error==UPLOAD_ERR_FORM_SIZE || $this->maxSize!==null && $file->getSize()>$this->maxSize)
{
$message=$this->tooLarge!==null?$this->tooLarge : Yii::t('yii','The file "{file}" is too large. Its size cannot exceed {limit} MB.');
$this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{limit}'=>$this->sizeToMegaBytes($this->getSizeLimit())));
}
else if($error==UPLOAD_ERR_PARTIAL)
throw new CException(Yii::t('yii','The file "{file}" was only partially uploaded.',array('{file}'=>$file->getName())));
else if($error==UPLOAD_ERR_NO_TMP_DIR)
throw new CException(Yii::t('yii','Missing the temporary folder to store the uploaded file "{file}".',array('{file}'=>$file->getName())));
else if($error==UPLOAD_ERR_CANT_WRITE)
throw new CException(Yii::t('yii','Failed to write the uploaded file "{file}" to disk.',array('{file}'=>$file->getName())));
else if(defined('UPLOAD_ERR_EXTENSION') && $error==UPLOAD_ERR_EXTENSION) // available for PHP 5.2.0 or above
throw new CException(Yii::t('yii','File upload was stopped by extension.'));
if($this->minSize!==null && $file->getSize()<$this->minSize)
{
$message=$this->tooSmall!==null?$this->tooSmall : Yii::t('yii','The file "{file}" is too small. Its size cannot be smaller than {limit} bytes.');
$this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{limit}'=>$this->minSize));
}
if($this->types!==null)
{
if(is_string($this->types))
$types=preg_split('/[\s,]+/',strtolower($this->types),-1,PREG_SPLIT_NO_EMPTY);
else
$types=$this->types;
if(!in_array(strtolower($file->getExtensionName()),$types))
{
$message=$this->wrongType!==null?$this->wrongType : Yii::t('yii','The file "{file}" cannot be uploaded. Only files with these extensions are allowed: {extensions}.');
$this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{extensions}'=>implode(', ',$types)));
}
}
}
private function sizeToMegaBytes($size)
{
$size = ($size/1048576*100000)/100000;
return $size;
}
}
y para descargar el archivo uso la extensión CDownload
/**
* @author Rasmus Schultz
* @link http://mindplay.dk
* @copyright Copyright © 2010 Rasmus Schultz
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
/**
* This class allows multi-threaded file downloads, and regular file
downloads.
*
* You can use this class when you need to control which users are allowed
to
* download a file from a protected area of the local filesystem.
*
* Note that downloading files in this way does result in some memory and
processor
* overhead - you should not use this class sporadically for all downloads
in your
* application, only when a regular download is not possible for some
reason (usually
* because the file in question must not be made available to the general
public).
*
* Avoid using this class when you need to log access to a public file -
you're
* probably better off using a pre-download logging action, which then
redirects to
* the actual file download.
*/
class CDownload {
/**
* Buffer size (memory requirement per download / user / thread)
*/
const BUFFER_SIZE = 32768; # = 1024*32
/**
* Time limit (time allowed to send one buffer)
*/
const TIME_LIMIT = 30;
/**
* Sends a file to the client.
*
* This is a blocking method, which means that the method-call will not
return until
* the client has completed the download of the file (or segment), or
until the client
* is disconnected and the connection/download is aborted.
*
* Check the return value of this method to see if the download was
successful - this
* if useful, for example, if you need to count and limit the number of
times a user can
* download a file; you should increase your counters only if the call
returns TRUE.
*
* It is important that your action produces <strong>no other
output</strong> before
* or after calling this method, as this will corrupt the downloaded
binary file.
*
* Output buffers will be cleared and disabled, and any active
CWebLogRoute instances
* (which might otherwise output logging information at the end of the
request) will
* be detected and disabled.
*
* If your application might produce any other output after your action
completes, you
* should suppress this by using the exit statement at the end of your
action.
*
* This method throws a CException if the specified path does not point
to a valid file.
*
* This method throws a CHttpException (416) if the requested range is
invalid.
*
* @param string full path to a file on the local filesystem being sent
to the client.
* @param string optional, alternative filename as the client will see it
(defaults to the local filename specified in $path)
* @return boolean true if the download succeeded, false if the
connection was aborted prematurely.
*/
public static function send($path, $name=null)
{
// turn off output buffering
@ob_end_clean();
// disable any CWebLogRoutes to prevent them from outputting at the end of the request
foreach (Yii::app()->log->routes as $route)
if ($route instanceof CWebLogRoute)
$route->enabled = false;
// obtain headers:
$envs = '';
foreach ($_ENV as $item => $value)
if (substr($item, 0, 5) == 'HTTP_')
$envs .= $item.' => '.$value."\n";
if (function_exists('apache_request_headers')) {
$headers = apache_request_headers();
foreach ($headers as $header => $value) {
$envs .= "apache: $header = $value\n";
}
}
// obtain filename, if needed:
if (is_null($name))
$name = basename($path);
// verify path and connection status:
if (!is_file($path) || !is_readable($path) || connection_status()!=0)
throw new CException('CDownload::send() : unable to access local file
"'.$path.'"');
// obtain filesize:
$size = filesize($path);
// configure download range for multi-threaded / resumed downloads:
if (isset($_ENV['HTTP_RANGE']))
{
list($a, $range) = explode("=", $_ENV['HTTP_RANGE']);
}
else if (function_exists('apache_request_headers'))
{
$headers = apache_request_headers();
if (isset($headers['Range'])) {
list($a, $range) = explode("=", $headers['Range']);
} else {
$range = false;
}
}
else
{
$range = false;
}
// produce required headers for partial downloads:
if ($range)
{
header('HTTP/1.1 206 Partial content');
list($begin, $end) = explode("-", $range);
if ($begin == '')
{
$begin = $size-$end;
$end = $size-1;
}
else if ($end == '')
{
$end = $size-1;
}
$header = 'Content-Range: bytes '.$begin.'-'.$end.'/'.($size);
$size = $end-$begin+1;
}
else
{
$header = false;
$begin = 0;
$end = $size-1;
}
// check range:
if (($begin > $size-1) || ($end > $size-1) || ($begin > $end))
throw new CHttpException(416,'Requested range not satisfiable');
// suppress client-side caching:
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Expires: ".gmdate("D, d M Y H:i:s", mktime(date("H")+2,
date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
// send a generic content-type:
header("Content-Type: application/octet-stream");
// send content-range header, if present:
if ($header) header($header);
// send content-length header:
header("Content-Length: ".$size);
// send content-disposition, with special handling for IE:
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE)
{
header("Content-Disposition: inline; filename=".str_replace(' ',
'%20', $name));
}
else
{
header("Content-Disposition: inline; filename=\"$name\"");
}
// set encoding:
header("Content-Transfer-Encoding: binary\n");
// stream out the binary data:
if ($file = fopen($path, 'rb'))
{
fseek($file, $begin);
$sent = 0;
while ($sent < $size)
{
set_time_limit(self::TIME_LIMIT);
$bytes = $end - ftell($file) + 1;
if ($bytes > self::BUFFER_SIZE)
$bytes = self::BUFFER_SIZE;
echo fread($file, $bytes);
$sent += $bytes;
flush();
if (connection_aborted())
break;
}
fclose($file);
}
// check connection status and return:
$status = (connection_status()==0) and !connection_aborted();
return $status;
}
}
Ojala te sirva nada mas faltaria indicar tus botones que lleguen al metodo donde vas a guardar y ese código es como el de Jack Fiallos. Saludos.