Em php para trabalhar com arquivos você precisa usar a super global $_FILES…
O conceito básico começa pelo formulário html…
<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="file" name="arquivo">
</form>
Após isso no php você pega assim…
<?php
//upload.php
$arquivo = $_FILES['arquivo']; //name do input enviado...
$cod_erro = $arquivo['error']; //deu zica um código diferente de zero virá...
$tipo = $arquivo['type']; //se quiser validar... text/plain, image/png, application/pdf, etc...
$tamanho = $arquivo['size']; //em bytes...
$nome = $arquivo['name']; //nome original...
$nome_temp = $arquivo['tmp_name']; //nome que o servidor usa...
$destino = "C:/arquivos/upload/" . $nome; //linux ou mac /tmp/arquivos/upload por exemplo..
$salvou = move_uploaded_file($nome_temp, $destino); //tenta gravar...
if ($salvou) {
echo 'Arquivo gravado com sucesso!';
} else {
echo 'Não foi possível salvar!'; //ver permissão de escrita na pasta de destino...
}
Você pode achar estranho o caminho em windows estar com barra normal C:/… mas isso evita o php se confundir, pois se usar contra-barra , você precisaria usar duas \ para cada \ que exisitr, ficaria feio na url…
C:\\\\arquivos\\upload...
Ou seja, muito complicado agora né? 
Todo arquivo enviado ao php fica numa pasta temporaria controlada pelo SO (por isso o uso do tmp_name)… depois você precisa trocar de pasta usando o nome real do arquivo, assim você finaliza o upload…
Se algo der errado no upload, o valor error é definido como disse acima (vide significado dos códigos na documentação), onde zero significa que tudo foi tranquilo, mas há outros que representam o não envio do arquivo por exemplo através de constantes predefinidas…
if ($erro == UPLOAD_ERR_NO_FILE) {
echo 'Nenhum arquivo foi enviado';
} else {
//prossegue com outras validações se quiser até usar move_uploaded_file...
}