Nos últimos dias, precisei configurar um servidor para rodar uma aplicação web que estou desenvolvendo e necessitava fazer com que, caso o meu servlet container (estou utilizando o Jetty) parasse de funcionar, um outro processo levantasse o Jetty. Isso é um problema bastante comum e deve existir N maneiras de se resolver. Como sou iniciante em linux, scripts, etc... Resolvi criar um shell script para resolver este problema e com isso aprender um pouco como funcionam as coisas no linux.
Os assuntos abordados para resolver esse problema são :
Agendamento de Tarefas no linux
Shell script
Shell script
Shell script é uma linguagem de script usada em vários sistemas operativos (operacionais), com diferentes dialetos, dependendo do interpretador de comandos utilizado. Um exemplo de interpretador de comandos é o bash, usado na grande maioria das distribuições GNU/Linux. (wikipedia)
Para identificar que o arquivo é um script é necessário que a linha inicial seja:
#!/bin/bash
Precisamos também setar a permissão para executar script:
$ chmod +x arquivo
Para executar o script basta digitar "./nome_do_script.sh".
Exemplo:
Crie um arquivo chamado "teste.sh" com o conteúdo abaixo, configure sua permissão e execute-o.
#!/bin/bash
echo Olá mundo!
Agora vamos ao nosso script para deixar o Jetty sempre em execução:
Script:
O script funciona da seguinte maneira:
Verifica se tem algum processo "java" rodando que contenha na sua linha de comando "jetty.port=9090", caso exista, o script não faz mas nada, caso não exista, ele irá verificar se existe uma pasta chamada "logs", se não existir, ela será criada e dentro dela conterá um arquivo de log informando quando ocorreu do Jetty não está rodando e armazena o "load average" do servidor naquele momento, logo após, executa o serviço do jetty novamente.
OBS: O load average vai me indicar superficialmente como estava o status do servidor no momento em que o Jetty caiu.
Agora, como fazer para agendar esse script para ser executado a cada X intervalo de tempo ?
Simples, adicionamos no serviço de agendamento do linux (cron) um agendamento para esse script.
Entendendo uma expressão cron
* * * * * [usuario] [comando]
Semântica dos valores de uma expressão cron:
- Minutos: Números de 0 a 59. - Horas: Números de 0 a 23. - Dias do mês: Números de 0 a 31. - Mês: Números de 1 a 12. - Dias da semana: Números de 0 a 7. - Usuário: Usuário que irá executar o comando (não é necessário especificá-lo se o arquivo do próprio usuário for usado). - Comando: Tarefa que será executada.
Nosso exemplo:
*/5 * * * * /caminho_do_seu_script/uptime.sh
Neste exemplo, o script de uptime será executado a cada 5 minutos.
Os agendamentos para seu usuário fica guardados em uma tabela chamada "crontab", para você poder adicionar um agendamento, apenas edite este arquivo adicionando o seu agendamento, para isto execute o comando abaixo:
$ crontab -e
Caso não exista agendamentos para o seu usuário, esse comando irá cria-ló. Se desejar ver os arquivos de agendamentos de cada usuário, você terá que logar como root e ir na pasta "/var/spool/cron/usuario".
Caso você deseje ver todos os agendamentos para seu usuário, digite:
No início de 2011 comprei um NAS modelo NS-K330 no DealExtreme e quando fiz o pedido já estava pensando em utilizá-lo de forma "não convencional". Para quem não conhece, um NAS (Network-Attached Storage) é, em linhas gerais, um dispositivo dedicado ao armazenamento e compartilhamento de arquivos e à disponibilização de serviços em uma rede. O NS-K330, além do preço sempre bacana do DX, tem as seguintes características:
Duas porta USB 2.0, permitindo que dispositivos como memórias flash e impressoras possam ser plugados ao aparelho;
Servidor de arquivos FTP;
Servidor de arquivos SAMBA;
Cliente BitTorrent, não sendo necessário que um computador fique ligado para que você possa baixar arquivos através de torrents;
Servidor de impressão compartilhado, permitindo que os usuários de uma rede acessem uma impressora conectada ao NAS;
Porta ethernet RJ45 10/100Mbps.
A primeira coisa que fiz quando o NAS chegou foi atualizar seu firmware, pois o original é fraquinho e cheio de bugs. Fiquei empolgado com o Snake OS, um projeto opensource, originalmente brasileiro, de um firmware para o NS-K330 e o WLXKJ652 baseado em Linux, o que no futuro ajudaria muito nos meus planos de extender o uso do NAS para alguns projetinhos malucos. Até aí tudo jóia, a atualização do firmware foi um sucesso e eu pude utilizar o aparelho durante bastante tempo na sua forma comum, principalmete seu cliente BitTorrent.
Problema
Em meados de agosto do ano passado, eu comecei a fuçar mais no NAS com o objetivo de disponibilizar na Internet as imagens de uma webcam USB conectada ao aparelho e que ficaria filmando o interior de minha casa. Superado este desafio, a falta de conectividade wireless no NAS passou a se tornar um problema e a me incomodar, pois eu queria colocar o aparelho e a webcam em um local em que um ponto de rede com fio seria inviável e apenas o acesso à rede wifi poderia resolver o problema. Para fazer isso eu precisaria ativar o módulo wireless do kernel utilizado pelo Snake OS e gerar um novo firmware para carregar no dispositivo.
Depois de muita pesquisa e apanhar bastante, consegui gerar um firmware com o kernel modificado para as minhas necessidades. O problema foi que quando fiz o upgrade meu NAS não "voltou" e parou de responder a qualquer tentativa de comunicação. Eu estava com um NS-K330 morto em mãos.
Recuperando o NAS
Antes de matar o NAS eu já havia lido algumas coisas sobre a recuperação do mesmo (procuro não fazer nada que possa matar um dispositivo antes de ter certeza que existe a possibilidade de trazê-lo de volta para este mundo). O wiki do Snake OS possui duas páginas que tratam de como estabelecer comunicação serial entre o NS-K330 e um computador e como regravar o firmware original. Foi este material que eu utilizei como guia e você pode acessar as páginas clicando aqui e aqui.
A única dificuldade que tive foi que o tutorial de recuperação da página do Snake OS descreve a utilização de um cabo USB de comunicação Nokia que já tem um hardware para conversão do nível TTL (utilizado pelo NAS) para RS232 (utilizado pelo computador). Como eu não tinha o cabo disponível e comprar no DX iria demorar horrores para chegar, resolvi montar um circuito na protoboard utilizando componentes que eu já tinha. É este procedimento que eu descrevo nos seguintes passos:
Primeiro passo
Desmonte o NAS e solde uma barra de pinos em sua placa. Na imagem abaixo é possível verificar onde ficam localizados os parafusos que fixam a carcaça do dispositivo:
Perceba que os parafusos estão localizados abaixo das borrachas que servem como pés para o aparelho. Você precisará retirar as quatro, tomando o cuidado de não danificá-las para que na montagem possa fixá-las novamente. A barra de pinos deve ser soldada na localização indicada a seguir:
Serão quatro pinos, nas ilhas demarcadas pelos quadrados em vermelho (VCC), preto (RX), preto (TX) e amarelo (GND). O VCC (primeiro pino da esquerda para a direita) não será utilizado.
Segundo passo
É necessário confeccionar os cabos de conexão com o NAS e com o computador. Para o primeiro, eu cortei um cabo de alimentação de disquete de uma fonte velha, para aproveitar o conector fêmea de quatro vias que se encaixa perfeitamente na barra de pinos soldada ao NS-K330. Para o segundo, eu precisei soldar três fios em um conector DB9 fêmea (pinos 2, 3 e 5) e a uma barra com três pinos. Os cabos prontos ficaram assim:
Terceiro passo
Com os cabos prontos e o NAS preparado para a conexão serial, é necessário montar o circuito de conversão do nível TTL para RS232 em uma protoboard. Os componentes eletrônicos necessários são:
MAX232 - Circuito integrado responsável por converter uma entrada TTL para uma saída RS232 e uma entrada RS232 para uma saída TTL;
4 capacitores eletrolíticos de 1uF;
Fonte de alimentação de 5VC - Eu utilizei meu Arduino Nano que tem saída de 5V simplesmente pela facilidade de uso, já que precisei apenas conectá-lo na USB, mas também pode ser usada, por exemplo, uma fonte ATX de PC.
O esquema elétrico ficou assim (clique na imagem para ampliar):
A montagem na protoboard pode ser vista a seguir (clique na imagem para ampliar):
Quarto passo
Agora conecte o NAS à protoboard e a portoboard à serial de um computador. O aspecto da montagem final ficou assim:
Antes de alimentar o NAS e a protoboard, é necessário abrir a porta serial do computador com as configurações 38400bps 8-N-1. Eu utilizei o putty para isso, mas você pode utilizar qualquer outra aplicação que realize uma comunicação serial, como por exemplo o HyperTerminal do Windows.
Ao ligar o NAS à energia, você verificará todo o processo de boot do firmware. No meu caso, estava ocorrendo um "Kernel panic" que impedia que o sistema operasse.
Quinto passo
Com a comunicação NAS - Computador funcionando, é hora de recuperar o dispositivo. Reinicie o NAS e interrompa o processo de boot através do pressionamento de qualquer tecla, então você terá o prompt "Star Equuleus #" do uboot.
Para baixar a imagem do boot de recuperação, você precisará de um servidor TFTP instalado no computador. No Ubuntu, precisei apenas instalar o pacote tftpd-hpa assim:
sudo apt-get install tftpd-hpa
Depois baixe o arquivo recovery.8132 (boot para recuperação) e coloque na raíz do servidor TFTP. No meu caso coloquei o arquivo no diretório padrão do tftpd-hpa /var/lib/tftpboot.
Ainda no computador, baixe o arquivo fw_def_mtd.zip (firmware original) e o extraia em um pendriver que será utilizado em seguida. Também configure o IP da placa de rede para 192.168.0.100. Não esqueça de conectar um cabo de rede do NAS para o computador.
No prompt do NAS, execute os seguintes comandos para configurar a interface de rede, baixar a imagem do boot de recuperação e executá-la:
O NAS deverá carregar o boot que você baixou. Aguarde então o processo ser concluído até o surgimento de um prompt (aqui eu precisei dar um enter no final do boot para que o prompt surgisse).
A recuperação ainda não está concluída. É necessário espetar o pendriver com o firmware original ao NAS, que será montado automaticamente em /usb/sda1. Depois deste procedimento, rode os seguintes comandos no prompt do NS-K330:
Estes comandos irão gravar as imagens do firmware original nas posições de memória corretas. Os dois últimos podem demorar um pouco mais de tempo. Aguarde o fim da gravação e reinicie o NAS removendo e recolocando o cabo de energia. Pronto, seu NAS está recuperado com o firmware e as configurações originais de fábrica.
Conclusão
O processo de recuperação do NAS NS-K330 é mais trabalhoso do que complexo. Uma vez montada a protoboard com o circuito de conversão de nível, a recuperação se resume a comandos no prompt do NAS. O processo pode ser simplificado com a aquisição e utilização do cabo sugerido no wiki do Snake OS.
Em caso de dúvidas, sinta-se a vontade para perguntar através da seção de comentários desta página.
Quarta feira, 19 de janeiro de 2012. Essa data pode representar um marco negativo na história da internet. E o dia já começou com várias manifestações, inclusive da Wikipédia, que tirou do ar sua página (versão inglesa) em protesto contra o SOPA.
A essa altura, muitos ainda devem estar se perguntando o que é o SOPA e como isso pode afetar a internet de um modo geral e nós, brasileiros. Neste post você vai entender melhor do que se trata.
A sigla significa "Stop Online Piracy Act" (Lei de Combate à Pirataria Online), e é um projeto de lei americano criado por Lamar Smith e um grupo de outros representantes do Congresso Americano. Esse projeto visa aumentar o poder de ação contra a pirataria online, em favor dos detentores de propriedade intelectual, e está sendo votado exatamente hoje. Outro projeto de lei similar que está para ser votado é o PIPA (Protect IP Act).
Se você parasse de ler por aqui, poderia até achar que está tudo bem. Porém, o meio principal de retaliação que a lei prevê é jogar a culpa sobre a pirataria nas empresas que prestam serviços de internet, e também em sites onde se pode compartilhar conteúdo - redes sociais, wikis, fóruns, qualquer blog onde se possa comentar... enfim, querem instituir um tipo de censura na internet, com poderes para tirar do ar qualquer site ou serviço que seja "considerado suspeito".
Quem se beneficia dessa lei? Claro que não somos nem eu nem você, nem os cidadãos americanos. As principais beneficiadas serão as grandes gravadoras e produtoras como Time Warner, Sony, CBS dentre outras, que são as maiores apoiadoras da lei.
E como isso afeta a nós, brasileiros?
Primeiramente, mais de metade da infraestrutura da web está em território americano. Inclusive este site, que é hospedado em um servidor de lá.
Além de uma enorme parcela dos sites brasileiros estar hospedada lá fora (custos muito menores, a maioria das empresas de hospedagem brasileiras alugam infraestrutura de fora), a lei prevê o direito de tirar do ar sites estrangeiros, sem a necessidade de uma ordem judicial para tanto. Basta ser considerado suspeito de pirataria. Ou seja, você tem o maior zelo pelo seu blog, mas de repente alguém deixa um comentário com um link que pode ser considerado pirataria - eles poderão tirar o seu site do ar, inteirinho.
Ok, você não tem um site. Mas com certeza você utiliza redes sociais (Facebook e cia). Também aposto que você já usou a Wikipedia para fazer pesquisas importantes. Ou tirou dúvidas em fóruns especializados sobre algum assunto. Já pensou como seria a internet sem estes sites? E sem um monte de outros sites, que poderiam ser tirados do ar por censura e/ou interesses de terceiros?
Estaríamos retrocedendo aos tempos em que o usuário não tem o direito de se manifestar, compartilhar, participar - afinal, que site deixaria espaço comunitário sob o risco de sair do ar caso algo fosse considerado "suspeito" pelos reguladores do SOPA? Quem vai ter coragem de expor sua opinião, compartilhar conteúdo, e sofrer retaliação? Seria o fim de comunidades e fóruns.
Abaixo, alguns trechos relevantes da carta aberta que a Wikimedia (fundação que mantém a Wikipedia) aos seus leitores e comunidade explicando sua posição e a razão do "blackout" de hoje.
"Nós dependemos de uma infra-estrutura legal que nos torna possível operar. E nós dependemos de uma infra-estrutura legal que também permite que outros sites hospedem conteúdo de contribuição de usuários(...) Esse conhecimento precisa ser publicado em algum lugar para que qualquer pessoa possa encontrá-lo e usá-lo. Quando ele pode ser censurado sem um devido processo, é uma agressão ao autor, ao público e à Wikimedia."
"Além disso,SOPAePIPAsão apenasindicadoresde um problemamuito mais amplo.Em todo o mundo, estamos vendoo desenvolvimento delegislação destinada acombater a piratariaonline,e regular aInternetde outras maneiras,que feremas liberdadesonline. Nossa preocupaçãose estende para além deSOPAePIPA:eles são apenasparte do problema. Queremos que aInternet permaneçalivre e aberta,em todos os lugares,para todos."
Update 1: apenas alguns sites que protestaram contra o SOPA / PIPA hoje. Só pra você ter noção que a bronca é grande mesmo.
O Google colocou um link em sua página principal que dá nessa página especial abaixo. "End Piracy, Not Liberty".
Fora inúmeros outros sites conhecidos (9gag, 4chan, gizmodo, wired) que protestaram com banners, tarjas pretas e coisas do tipo.
Por enquanto, a melhor coisa que podemos fazer é nos manter informados, e informar outras pessoas sobre o assunto. A coisa é séria e não pode ser relegada a segundo plano. Nossa liberdade está em jogo.
Update 2: o SOPA voltará a ser debatido daqui a duas semanas (em fevereiro). Durante esse período, o projeto será avaliado pelos partidos Democrata e Republicano.
No mês passado tive a oportunidade de palestrar no IV Encontro de Comunicação Digital, realizado no IFPB. O tema da palestra foi uma introdução sobre a plataforma Arduino e entre outras coisas, falei um pouco sobre computação física, sistemas embarcados e microcontroladores. No final da palestra apresentei um protótipo, feito especialmente para o evento, para passar slides utilizando um controle remoto comum. Se trata de um projeto introdutório, mas que pode ser utilizado para simular eventos em um computador através de um controle.
O projeto foi desenvolvido em duas partes, onde a primeira parte é responsável por receber os dados enviados pelo controle remoto e transmiti-los via USB(RS232), e a segunda parte é responsável por receber os dados via USB, interpreta-los e realizar alguma ação de acordo com o dado recebido. Para compor a primeira parte do projeto foi utilizado um Arduino UNO e um receptor infravermelho, retirado de um aparelho de DVD antigo. A segunda parte, que recebe os dados do Arduino, foi desenvolvida em Python e utilizando o comando xdotool, já apresentado aqui em outro post. Apesar do projeto ter sido testado apenas no Linux, ele pode ser facilmente adptado para funcionar em outros sistemas operacionais.
A ligação do receptor infravermelho ao Arduino é bastante simples, pois dispensa a utilização de componentes extras (resistores, capacitores etc), bastando apenas conectá-lo aos pinos corretos. Na foto abaixo podemos ver a ligação entre o Arduino e o receptor infravermelho, neste caso conectado aos pinos D11, GND e VCC(5V) do Arduino.
Com esse código, o Arduino consegue receber os sinais infravermelhos enviados pelo controle remoto, convertê-los em uma sequência hexadecimal e enviá-los pela porta serial. Dessa forma, quando o Arduino estiver ligado e um botão do controle remoto for pressionado, um código hexadecimal, correspondente ao botão pressionado, será enviado pela porta serial que está conectada ao PC.
Para receber os dados enviados pelo Arduino, interpretá-los e simular ações de teclado, foi desenvolvido um simples código Python. A ferramenta xdotool é utilizada pelo código para simular ações de teclado e mouse, portanto é indispensável para o correto funcionamento da aplicação. Abaixo segue o código desenvolvido:
Após executar o código Python, serão exibidas mensagens na tela solicitando o pressionamento dos botões do controle remoto que serão associados as teclas de navegação do teclado do computador (Left, Right, Down e Up). Depois de associar o botões corretamente, basta pressionar o botão do controle associado a tecla que se deseja. O projeto completo pode ser visto em funcionamento no video abaixo:
Continuando minhas aventuras com o Arduino Nano (veja o post anterior clicando aqui), resolvi explorar um pouco mais a API para controle de motores servos, movimentando minha engenhoca com a ajuda de um joystick que eu tinha encostado em algum lugar aqui de casa. Esta etapa irá me ajudar no futuro a movimentar uma câmera remotamente em um projeto que estou trabalhando, mas por ora meu objetivo é controlar os dois motores servos através de um joystick tendo o meu notebook como "meio de campo" entre o Arduino e o controle.
Do primeiro post eu aproveitei as conexões na protoboard dos motores com o Arduino. Nesta etapa precisei implementar um aplicação em Python para capturar os eventos do joystick e enviar as coordenadas ao Arduino, que teve seu firmware alterado para receber as informações e movimentar os servos de acordo com as mesmas. O joystick que utilizei foi um Leadership Pilot Pro, mas você pode usar qualquer outro que tenha interface de comunicação com seu computador.
*Meu ambiente de desenvolvimento roda em cima do Ubuntu, então este post pode ser direcionado em alguns momentos para o sistema operacional Linux.
A aplicação em Python
Meu primeiro desafio foi encontrar a forma mais fácil de capturar as coordenadas dos eixos do meu joystick. Escolhi desenvolver uma aplicação em Python por conhecer a existência de uma biblioteca de nome pygameque abstrai muito do trabalho que eu teria se fosse utilizar uma linguagem de mais baixo nível. Caso você esteja em um Ubuntu, basta executar a seguinte linha no shell para instalar a biblioteca:
sudo apt-get install python-pygame
Além disso, esbarrei na internet com um código em Python no Principia Labs com o propósito bem semelhante ao proposto neste post e que eu acabei utilizando como referência. Você pode acessá-lo clicando aqui. Após algumas alterações para adequar o código ao uso de dois motores servos, tenho o seguinte programa:
#!/usr/bin/env python
#coding: utf-8
import serial, pygame, struct
joy = []
usbport = "/dev/ttyUSB0"
arduino = serial.Serial(usbport, 9600)
def handleJoyEvent(e):
if e.type == pygame.JOYAXISMOTION:
axis = "unknown"
if (e.dict['axis'] == 0):
axis = "X"
if (e.dict['axis'] == 1):
axis = "Y"
if (e.dict['axis'] == 2):
axis = "Throttle"
if (e.dict['axis'] == 3):
axis = "Z"
if (axis == "X") or (axis == "Y"):
pos = e.dict['value']
move = round(pos * 90, 0)
if (move < 0):
servo = int(90 + abs(move))
else:
servo = int(90 - move)
toSend = struct.pack("BB", ord(axis), servo)
arduino.write(toSend)
print axis, servo
elif e.type == pygame.JOYBUTTONDOWN:
if (e.dict['button'] == 0):
arduino.close()
quit()
else:
pass
def joystickControl():
while True:
e = pygame.event.wait()
if (e.type == pygame.JOYAXISMOTION or e.type == pygame.JOYBUTTONDOWN):
handleJoyEvent(e)
def main():
pygame.joystick.init()
pygame.display.init()
if not pygame.joystick.get_count():
print "Por favor, conecte um joystick e tente novamente."
quit()
print "%d joystick(s) detectado(s)." % pygame.joystick.get_count()
for i in range(pygame.joystick.get_count()):
myjoy = pygame.joystick.Joystick(i)
myjoy.init()
joy.append(myjoy)
print "Joystick %d: " % (i) + joy[i].get_name()
print "Pressione o gatilho (botão 0) para sair."
joystickControl()
if __name__ == "__main__":
main()
Este código inicia e monitora as ações de todos os joysticks conectados ao computador e configura a porta /dev/ttyUSB0 para comunicação serial 8N1 a 9600bps. Esta é a porta que será utilizada para enviar dados ao Arduino (mais a frente explicarei como esta comunicação serial ocorre).
Quando um evento é detectado no joystick que tenho conectado ao notebook, a função handleJoyEvent é chamada para tratá-lo e uma verificação de qual eixo ou botão disparou o evento é realizada. Quando os eixos X e Y são alterados, dois bytes são enviados ao Arduino. O primeiro byte representa o eixo movimentado (caractere 'X' ou caractere 'Y') e o segundo byte representa a posição do eixo já convertida para um ângulo entre 0 e 180. Quando o botão 0 é pressionado (o gatilho no caso do meu controle), a aplicação é encerrada.
O firmware do Arduino
Por último precisei escrever um programa para que o Arduino recebesse através de comunicação serial as coordenadas X e Y para movimentação dos servos. Antes de continuar, preciso dizer que o cabo USB do Arduino comporta-se como um adaptador serial, disponibilizando em minha máquina o dispositivo /dev/ttyUSB0, já mencionado. O código ficou assim:
A utilização da biblioteca Servo já foi explicada no post anterior. O que temos de novidade no setup é a configuração da comunicação serial com a velocidade 9600bps. No loop temos a verificação da disponibilidade de dois bytes ou mais para leitura na serial e quando esta condição for verdadeira é realizada a captura do nome do eixo a ser movimentado (variável axis) e seu ângulo (variável grau). Perceba que coloquei uma limitação para a movimentação do servo responsável pelo eixo Y. Acontece que eu devo ter cometido algum erro na montagem do pan tilt (componente mecânico com dois servos instalados e que pode ser visto no meu post anterior), por isso tem um parafuso impedindo que o servo se posicione em ângulos muito abertos (menores que 20 e maiores que 170 graus). Problema "contornado", segue abaixo o vídeo que gravei com os dois programas rodando (perdoem a qualidade, estou providenciando outra câmera):
Na próxima etapa conectarei o Arduino a um NAS modificado para que seja possível movimentar os servos de forma remota. Nos próximos dias postarei alguns conteúdos relacionados ao NAS, preparando-o para a conexão com o Arduino.
Há poucos dias precisei de uma solução que compartilhasse imagens diretamente no facebook do usuário, e descobri que é bastante fácil implementar essa funcionalidade em php. A maior dificuldade que enfrentei foi com relação ao meu servidor, que apesar de ter a lib Curl já instalada e em funcionamento (as aplicações para o Twitter que eu criei já se utilizam dela há tempos), para usar a biblioteca php que o Facebook disponibiliza era preciso que a lib Curl estivesse compilada com suporte a SSL. Tive que pedir um help a Hugo Reinaldo que resolveu rapidinho o problema pra mim ;)
Com esse problema resolvido, parti para o código php. Usei um exemplo que encontrei no Google, mas ele não estava funcionando corretamente. Dei uma pesquisada na documentação da API do Facebook e consegui corrigir os erros e colocar o código pra funcionar. Então, vou disponibilizar o passo a passo pra vocês. Estou levando em consideração que você já tem um servidor pronto (com a lib Curl + SSL devidamente compilada).
Pra ficar mais "fancy", coloquei um formulário onde você envia uma imagem e escolhe um efeito para aplicar nela antes de publicar no seu Facebook.
Acesse http://developers.facebook.com e crie uma aplicação. São necessárias apenas duas informações: o nome da aplicação e o "namespace", que é como uma espécie de login, deve ser sem caracteres especiais ou espaços.
Agora é preciso informar ao Facebook o que a sua aplicação vai fazer. No nosso caso iremos apenas utilizar o login de usuário, ou seja, vamos autenticar o usuário pela nossa página e fazer operações na conta do usuário através desta página, fora do Facebook. Marque a opção "Website" e informe a url do site que irá autenticar o usuário (não é uma url de callback, é apenas a url geral do site mesmo. o callback é definido pelo código).
2. Código
Agora que a aplicação está criada, vamos ao código. Antes de mais nada, é preciso fazer download da sdk oficial do Facebook para php. Depois de baixar o zip, coloque os arquivos que estão no diretório SRC (você só vai precisar deles - base_facebook.php, facebook.php e fb_ca_chain_bundle.crt) em uma pasta no seu site (vamos usar uma pasta "facebook" na raiz do site para os exemplos) para podermos incluir no código.
A primeira coisa que você precisa fazer é incluir a lib facebook.php e definir os dados de configuração da sua aplicação, passando o app id e o app secret que você obtém ao registrá-la. Fica logo no início da tela de informações sobre a aplicação.
Depois de configurar o objeto facebook, você deve verificar se o usuário já está logado, e, caso ainda não esteja, obter o link para que ele faça login no facebook. Repare que ao solicitar o link de autenticação ao Facebook, eu passei o parâmetro "scope", com as permissões que vou precisar do usuário (user_status, publish_stream, user_photos) - pois vamos precisar dessas permissões para publicar em sua timeline.
$user = $facebook->getUser();
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
if($user)
$logoutUrl = $facebook->getLogoutUrl();
else
{
$params = array("scope"=> 'user_status, publish_stream, user_photos');
$loginUrl = $facebook->getLoginUrl($params);
}
if($loginUrl)
{
echo '<p>Você ainda não está logado. Clique no botão abaixo para logar com seu Facebook.</p>';
echo '<p><a href="'.$loginUrl.'" title="login with your facebook account"><img src="facebook-connect-button.png" /></a></p>';
}
else
{
echo '<p>Você está logado como <a href="'.$user_profile['link'].'">'.$user_profile['name']. '</a>. <a href="'.$logoutUrl.'">Clique aqui para fazer logout</a>.</p>';
//usuário está logado. exibir formulário
}
A parte da publicação no Facebook é bastante simples. Ao receber a imagem por upload, passamos diretamente o seu caminho tmp e postamos:
$filepath = realpath($_FILES['foto']['tmp_name']);
$photo = $facebook->api('/me/photos', 'POST',
array(
'source' => '@' . $filepath,
'message' => $_POST['legenda']
)
);
echo '<p>Montagem publicada com sucesso no seu Facebook :). <a href="http://www.facebook.com/photo.php?fbid='.$photo['id'].'" target="_blank">Clique aqui para visualizar</a>.</p>';
Agora o código completo, com a parte de efeitos usando a lib GD e os detalhes restantes - formulário, etc...
<?php
session_start(); //essencial
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="pt" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="reply-to" content="erika@entrebits.com.br" />
<meta name="robots" content="index,follow" />
<meta name="revisit-after" content="1" />
<meta name="classification" content="entretenimento" />
<meta name="distribution" content="global" />
<meta name="rating" content="general" />
<meta name="language" content="pt-br" />
<meta name="title" content="SharetoFace" />
<meta name="description" content="Facebook php share example" />
<meta name="keywords" content="facebook, share, example, php, app" />
<meta name="author" content="Erika"/>
<meta name="copyright" content="ErikaHeidi" />
<title>FaceShare - entrebits labs</title>
<style>
body {
background-color: #E5E5E5;
text-align: center;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
}
form {
padding: 10px;
text-align: left;
margin: 0 auto;
border: 1px solid #CCC;
}
small {
font-size: 10px;
}
</style>
<?php
require_once('facebook/facebook.php');
$facebook = new Facebook(array(
'appId' => "SEU_APP_ID",
'secret' => "SEU_APP_SECRET",
'cookie' => true,
'fileUpload' => true
));
$user = $facebook->getUser();
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
if($user)
$logoutUrl = $facebook->getLogoutUrl();
else
{
$params = array("scope"=> 'user_status, publish_stream, user_photos');
$loginUrl = $facebook->getLoginUrl($params);
}
if($loginUrl)
{
echo '<p>Você ainda não está logado. Clique no botão abaixo para logar com seu Facebook.</p>';
echo '<p><a href="'.$loginUrl.'" title="login with your facebook account"><img src="facebook-connect-button.png" /></a></p>';
}
else
{
echo '<p>Você está logado como <a href="'.$user_profile['link'].'">'.$user_profile['name']. '</a>. <a href="'.$logoutUrl.'">Clique aqui para fazer logout</a>.</p>';
//usuário está logado. exibir formulário
?>
<form method="post" enctype="multipart/form-data">
<input type="hidden" name="submitted" value="1" />
<p>Foto (jpg): <input type="file" name="foto" /></p>
<p>Aplicar efeito:
<select name="efeito">
<option value="col">Estou com Sorte</option>
<option value="pb">Preto e Branco</option>
<option value="sep">Sépia</option>
<option value="0">Nenhum</option>
</select>
</p>
<p>Legenda: <input type="text" name="legenda" /></p>
<p><input type="submit" value="Postar no Facebook" />
</form>
<?
}
if($_POST['submitted'])
{
//compartilhar imagem
$filepath = realpath($_FILES['foto']['tmp_name']);
if($_POST['efeito'])
{
$im = imagecreatefromjpeg($filepath);
switch($_POST['efeito'])
{
case "pb":
imagefilter($im, IMG_FILTER_GRAYSCALE);
break;
case "sepia":
imagefilter($im, IMG_FILTER_COLORIZE, 90, 60, 40);
imagefilter($im, IMG_FILTER_CONTRAST, 10);
break;
case "col":
imagefilter($im, IMG_FILTER_COLORIZE, rand(0,255), rand(0,255), rand(0,255));
break;
}
imagejpeg($im,$filepath,95);
}
// add a status message
$photo = $facebook->api('/me/photos', 'POST',
array(
'source' => '@' . $filepath,
'message' => $_POST['legenda']
)
);
echo '<p>Montagem publicada com sucesso no seu Facebook :). <a href="http://www.facebook.com/photo.php?fbid='.$photo['id'].'" target="_blank">Clique aqui para visualizar</a>.</p>';
}
?>