Archive for fevereiro \27\-02:00 2013

PostgreSQL: Script to generate audit trail tables

Posted on fevereiro 27, 2013. Filed under: PHP, PostgreSQL | Tags:, , |

Introduction
I created a php script to generate all tables/functions and triggers needed to audit trail as shown in the article Audit Trail for Postgres

The script

These script will connect to your database and write out the sql commands to create the tables/functions and triggers needed for audit of all tables. Adapt the script to your needs.

<?php
try {
        // configure database access parameters
        $host = "";
        $dbname = "";
        $user = "";
        $pass = "";
        $dbh = new PDO("pgsql:host=$host;dbname=$dbname", $user, $pass);

        $table_list = get_all_table_list();
        foreach($table_list as $table) {
                echo "--- TABLE $table";
                echo PHP_EOL;
                echo PHP_EOL;
                echo gen_create_table_audit($table);
                echo gen_create_function_audit($table);
                echo gen_create_trigger_audit($table);
                echo PHP_EOL;
        }

} catch (PDOException $e) {
        print "Error!: " . $e->getMessage() . "<br/>";
        die();
}

/**
 * Returns all table list from database
 */
function get_all_table_list() {
        global $dbh;

        $sql = "SELECT relname FROM pg_class
                 WHERE relname !~ '^(pg_|sql_)' AND relname !~ '_audit$'
                   AND relkind = 'r'";

        $table_list = array();
        foreach($dbh->query($sql) as $row) {
                array_push($table_list, $row['relname']);
        }
        return $table_list;
}

/**
 * generate create table for audit table
 */
function gen_create_table_audit($tablename) {
        global $dbh;

        $sql = "SELECT ordinal_position,
                 column_name,
                 data_type,
                 column_default,
                 is_nullable,
                 character_maximum_length,
                 numeric_precision
            FROM information_schema.columns
           WHERE table_name = '$tablename'
        ORDER BY ordinal_position";

        $tablename_audit = "{$tablename}_audit";

        $s = "--- Create table $tablename_audit" . PHP_EOL;
        $s .= "CREATE TABLE {$tablename_audit} (" . PHP_EOL;
        $s .= "\taudit_id serial PRIMARY KEY," . PHP_EOL;
        $s .= "\toperation char(1) NOT NULL," . PHP_EOL;
        $s .= "\tstamp timestamp NOT NULL," . PHP_EOL;
        $s .= "\tdbuser text NOT NULL," . PHP_EOL;

        foreach($dbh->query($sql) as $row) {
                extract($row);
                $character_maximum_length = trim($character_maximum_length);
                if (!empty($character_maximum_length)) {
                        $size = "(" . $character_maximum_length . ")";
                } else {
                        $size = "";
                }

                $null = ($is_nullable == "YES") ? "NULL" : "NOT NULL";
                $s .= "\t$column_name {$data_type}{$size} $null," . PHP_EOL;
        }

        $s = substr($s, 0, -2) . PHP_EOL;
        $s .= ");" . PHP_EOL;
        return $s;
}

/**
 * Generate create function for audit table
 */
function gen_create_function_audit($tablename) {

        $tablename_audit = "{$tablename}_audit";
        $functionname = $tablename_audit;

        $s = "--- Create function $functionname
CREATE OR REPLACE FUNCTION $functionname() RETURNS TRIGGER AS \$audit\$
    BEGIN
        IF (TG_OP = 'DELETE') THEN
            INSERT INTO $tablename_audit VALUES (DEFAULT, 'D', now(), user, OLD.*);
            RETURN OLD;
        ELSIF (TG_OP = 'UPDATE') THEN
            INSERT INTO $tablename_audit VALUES (DEFAULT, 'U', now(), user, NEW.*);
            RETURN NEW;
        ELSIF (TG_OP = 'INSERT') THEN
            INSERT INTO $tablename_audit VALUES (DEFAULT, 'I', now(), user, NEW.*);
            RETURN NEW;
        END IF;
        RETURN NULL; -- result is ignored since this is an AFTER trigger
    END;
\$audit\$ LANGUAGE plpgsql;";
        $s .= PHP_EOL;
        return $s;
}

/**
 * Generate create trigger for audit table
 */
function gen_create_trigger_audit($tablename) {
        $tablename_audit = "{$tablename}_audit";
        $triggername = $tablename_audit . "t";
        $functionname = $tablename_audit;

        $s = "--- Create trigger $triggername" . PHP_EOL;
        $s .= "CREATE TRIGGER $triggername AFTER INSERT OR UPDATE OR DELETE ON $tablename FOR EACH ROW EXECUTE PROCEDURE $functionname();";
        $s .= PHP_EOL;
        return $s;
}

Example of how to use the script:

$ php audit.php > audit.sql

Example Output:

--- TABLE minuser

--- Create table minuser_audit
CREATE TABLE minuser_audit (
        audit_id serial PRIMARY KEY,
        operation char(1) NOT NULL,
        stamp timestamp NOT NULL,
        dbuser text NOT NULL,
        user_id uuid NOT NULL,
        user_name character varying(50) NOT NULL,
        user_password character varying(50) NOT NULL,
        user_email character varying(50) NULL,
        user_role character varying(50) NULL
);
--- Create function minuser_audit
CREATE OR REPLACE FUNCTION minuser_audit() RETURNS TRIGGER AS $audit$
    BEGIN
        IF (TG_OP = 'DELETE') THEN
            INSERT INTO minuser_audit VALUES (DEFAULT, 'D', now(), user, OLD.*);
            RETURN OLD;
        ELSIF (TG_OP = 'UPDATE') THEN
            INSERT INTO minuser_audit VALUES (DEFAULT, 'U', now(), user, NEW.*);
            RETURN NEW;
        ELSIF (TG_OP = 'INSERT') THEN
            INSERT INTO minuser_audit VALUES (DEFAULT, 'I', now(), user, NEW.*);
            RETURN NEW;
        END IF;
        RETURN NULL; -- result is ignored since this is an AFTER trigger
    END;
$audit$ LANGUAGE plpgsql;
--- Create trigger minuser_auditt
CREATE TRIGGER minuser_auditt AFTER INSERT OR UPDATE OR DELETE ON minuser FOR EACH ROW EXECUTE PROCEDURE minuser_audit();
Ler Post Completo | Make a Comment ( None so far )

Facebook sdk, Publicando fotos na Fan Page com access token.

Posted on fevereiro 9, 2013. Filed under: Facebook, PHP | Tags:, , , |

Introdução

Vou apresentar aqui uma maneira de você trabalhar com postagem de fotos em fan page de forma automática. O script final apresentado aqui poderá usado diretamente no crontab.

Já havia demonstrado essa função em um artigo anterior: Facebook app, publicando fotos na fanpage com access token. Porém aquele método já se tornou obsoleto devido mudanças ocorridas no site do facebook.

Access Token

Para poder criar o script de publicação automatizado, primeiro temos que ter um access token de usuário. O access token do usuário será gerado uma única vez. Depois vamos parametrizar esse access token no segundo script. Fique atento que esse access token do usuário tem um tempo de expiração, normalmente são 60 dias. Isso significa que depois de 60 dias, você terá que gerar o access token novamente, usando o primeiro script, e depois atualizando o segundo script.

Portanto, vamos trabalhar esse artigo em duas etapas:
1 – Obter o access token do usuário administrador da fanpage, que tem um tempo de expiração de 60 dias.
2 – Script para publicar na fan page utilizando o access token do usuário obtido na primeira etapa.

  1. Obtendo o access token do usuário administrador da fan page
  2. Para obter o access token do usuário, vamos precisar:

    • Ter uma aplicação criada no facebook com o mesmo usuário que é administrador da fan page. Para saber como criar aplicações no facebook, acessar meu artigo Criando aplicativos para Facebook usando SDK do PHP
    • Acessar a aplicação criada abaixo com o mesmo usuário que você criou a aplicação e que também é administrador da fan page. Ao acessar o script abaixo, você terá o access token e a data/hora de expiração do token. É interessante anotar essa data para saber quando você terá que executar o script novamente.
    • Não se esqueça de parametrizar o APP_ID e o SECRET da sua aplicação logo no início do script.
    <?php
    // biblioteca do facebook
    require 'src/facebook.php';
    
    // ATENCAO, configurar os parametros abaixo
    $APP_ID = ""; // id da app
    $SECRET = ""; // secret da app
    $PERMS = "publish_stream,manage_pages";
    
    // objeto do facebook
    $facebook = new Facebook(array(
      'appId'  => $APP_ID,
      'secret' => $SECRET,
    ));
    
    // monta URL atual
    $my_url = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    
    // obtem CODE da autenticacao OAUTH
    $code = $_REQUEST['code'];
    if(empty($code)) {
            $dialog_url = "https://www.facebook.com/dialog/oauth?client_id="
                   . $APP_ID . "&redirect_uri=" . urlencode($my_url)
                   . "&scope=$PERMS";
    
            header("Location: $dialog_url");
            exit;
    }
    
    // com o CODE vamos gerar a URL para obter o access token do usuario
    $token_url = "https://graph.facebook.com/oauth/access_token?"
           . "client_id=" . $APP_ID . "&redirect_uri=" . urlencode($my_url)
           . "&client_secret=" . $SECRET . "&code=" . $code;
    
    $response = file_get_contents($token_url);
    $params = null;
    parse_str($response, $params);
    
    // printando o access token e quando ele ira expirar
    echo "Access Token: ";
    echo $params['access_token'];
    echo "<br />";
    if (!empty($params["expires"])) {
            echo "Ir&aacute; expirar em: " . date("d/m/Y H:i:s", time() + $params["expires"]);
    }
    
    

    Observações:

    • Ao acessar a app pela primeira vez, aceitar todas as permissões solicitadas.
    • É comum a pratica de guardar o valor do access token em uma tabela do banco de dados.
  3. Script automatizado que publica fotos diretamente na fan page
  4. Vamos agora ao script que publica diretamente as fotos na fan page. É importante que você tenha em mãos o id da fan page que deseja publicar as fotos. Para obter o ID da fan page é bem simples. Basta acessar a página da fan page com o usuário administrador, clicar em Editar Página -> Atualizar Informações. O id da fan page estará na URL do navegador.

    Atente-se para preencher os outros parâmetros necessários: APP_ID, SECRET, ACCESS_TOKEN do usuário.

    No exemplo abaixo, tem também um caminho para a imagem que será enviada para a fan page. Personalize o script de acordo com sua necessidade, criando sua própria rotina que seleciona as imagens desejadas.

    <?php
    // biblioteca do facebook
    require 'src/facebook.php';
    
    // ATENCAO, configurar os parametros abaixo
    $APP_ID = ""; // id da app
    $SECRET = ""; // secret da app
    $FANPAGE_ID = ""; // id da fanpage que vai publicar
    $IMAGEM_UPLOAD = "image.jpg"; // local do arquivo de imagem do upload
    $ACCESS_TOKEN = ""; // token obtido pelo gera-token.php
    
    // objeto do facebook
    $facebook = new Facebook(array(
      'appId'  => $APP_ID,
      'secret' => $SECRET,
    ));
    
    // obtendo o access token da fanpage a partir do access token do usuario administrador
    $graph_url = "https://graph.facebook.com/me/accounts?access_token=" . $ACCESS_TOKEN;
    $accounts = json_decode(file_get_contents($graph_url));
    
    $FANPAGE_ACCESS_TOKEN = null;
    foreach($accounts->data as $result) {
            if($result->id == $FANPAGE_ID) {
                    $FANPAGE_ACCESS_TOKEN = $result->access_token;
            }
    }
    
    // encontrou o access token da fanpage
    if($FANPAGE_ACCESS_TOKEN) {
            // determina que sera realizado upload de arquivos
            $facebook->setFileUploadSupport(true);
    
            try {
                    // parametros da postagem
                    $post_data = array(
                            "message" => "teste_" . time(),
                            "image" => '@' . realpath($IMAGEM_UPLOAD),
                            'access_token' => $FANPAGE_ACCESS_TOKEN,
                    );
    
                    // postando a imagem na fanpage
                    $data['photo'] = $facebook->api("/$FANPAGE_ID/photos", 'post', $post_data);
                    echo "publicado com sucesso";
    
            } catch (FacebookApiException $e) {
                    var_dump($e);
                    $user = null;
            }
    }
    

O script acima poderá ser inserido no crontab usando um navegador modo texto do linux como lynx ou links. Lembre-se que a única manutenção que precisa fazer é gerar o access token do usuário a cada 60 dias.

Boa sorte!

Ler Post Completo | Make a Comment ( 5 so far )

Java, acessando banco de dados MS-Access em Windows 64bits

Posted on fevereiro 2, 2013. Filed under: Access, Java | Tags:, , , |

Introdução

Neste artigo vamos aprender como acessar um banco de dados MS-Access pelo Java. No caso, estaremos com o Windows instalado em uma arquitetura 64bits. Mesmo estando na arquitetura 64bits, o Windows ainda distribui os drivers ODBC do MS-Access em arquitetura 32bits (Pelo menos no Windows 7). Portanto, para que o Java possa usar o driver ODBC do Ms-Access, teremos que rodar o Java em uma JVM de arquitetura 32bits.

Configurando o ODBC

O primeiro passo é configurar um data source no administrador de fonte de dados ODBC do Windows. Como estamos usando o Windows 64bits, abra o odbcad32.exe no seguitne caminho:
C:\Windows\SysWOW64\odbcad32.exe

PS: Não acesse o odbcad32.exe dentro do diretório System32, pois não funcionará corretamente devido a arquitetura do Windows ser 64bits.

Após aberto o gerenciador de fonte de dados, clique na aba “Fonte de dados do Sistema”, em seguida, clique no botão Adicionar, para adicionar uma nova fonte de dados.

ScreenShot048

Selecione o Microsoft Access Driver como tipo de driver para fonte de dados. No meu caso, preciso conectar em um banco de dados MS-Access com extensão .accdb:

ScreenShot049

Na próxima tela informe o nome da fonte de dados. Esse nome será usado para identificar o banco de dados na hora do acesso (Vamos usar esse nome em nosso programa Java).

Clique no botão Selecionar e escolha o banco de dados MS-Access. (No meu caso é um arquivo com extensão .accdb) e clicar em OK:

ScreenShot050

Criando o aplicativo Java

O código abaixo é um exemplo de como fazer o Java conectar em um banco de dados MS-Access. Verificar no próprio código, os comentários para qualquer dúvida.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


/**
 * Classe responsável por gerenciar conexões com banco de dados MS-Access
 * @author Douglas.Pasqua
 *
 */
public class AccessConnect {
	private static final String username = "";
	private static final String password = "";
	private static final String DSN = "DatabaseUsuarios"; // nome da fonte de dados
	private static final String driver = "sun.jdbc.odbc.JdbcOdbcDriver"; // driver usado
	private static Connection conn = null;
	        
	/**
	 *  retorna uma conexão com o banco de dados Access. 
	 *  Utiliza o Design Pattern Singleton
	 */ 
	public static Connection getConnection() throws Exception {
	    if(conn == null) {
	        String url = "jdbc:odbc:" + DSN;
	        Class.forName(driver);
	        conn = DriverManager.getConnection(url, username, password);
	    }
	    return conn;
	}
	
	/**
	 * Fecha a conexão com o Banco de dados access
	 * Chamar esse método ao sair da aplicação
	 */
	 public static void close() {
        if(conn != null) {
            try {
                conn.close();
            } catch (SQLException ex) {
                ex.printStackTrace();
            } finally {
                conn = null;
            }
        }
    }
	
	/**
	 * Exemplo de teste da classe de conexão com o 
	 * Access
	 */
	public static void main(String[] args) {
		try {
			// inicilizando a conexão
			Connection conn = AccessConnect.getConnection();

			Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("SELECT nome FROM usuario"); // temos uma tabela usuario com o campo nome
            while(rs.next()) {
            	String nome = rs.getString("nome");
                System.out.println("Nome: " + nome);
            }
            
            // fechando a conexão
			AccessConnect.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Ao executar o código acima, caso esteja em uma arquitetura 64bits, provavelmente a jvm usada também estará em 64bits, você obterá a seguinte Exception:

java.sql.SQLException: [Microsoft][ODBC Driver Manager] O DSN especificado contém uma incompatibilidade de arquiteturas entre o Driver e o Aplicativo

Como os drivers nativos do MS-Access no windows são 32bits e você esta executando o código em uma virtual machine do java em 64bits, será gerado o Exception acima. Para que você possa rodar o aplicativo sem erros, é necessário instalar o JRE do java para 32bits.

Instalando o JRE para 32bits

Para instalar o JRE versão 32bits para windows, acesse o link abaixo primeiramente:
http://www.oracle.com/technetwork/java/javase/downloads/index.html

Clique no download de JRE na versão desejada. Na próxima tela escolha a versão do java para x86. Exemplo:
jre-7u11-windows-i586.exe

Não se preocupe caso já tenha outra versão do java instalada. Não haverá conflitos. Após a instalação do JRE para 32bits, o próximo passo é executar o seu aplicativo java com essa nova jvm recém-instalada. Veremos abaixo como fazer através de linha de comando, Netbeans e Eclipse.

Executando através de linha de comando

Executar o java de 32bits através da linha de comando é simples. Basta usar o comando java do JRE de 32bits recém-instalado.
(Lembre-se que o importante é executar o bytecode do java em arquitetura 32bits. O compilador do java, javac, pode estar em outra arquitetura)

"C:\Program Files (x86)\Java\jre7\bin\java" -cp . AccessConnect

Executando através do Netbeans

No diretório bin\ da instalação do Netbeans tem dois executáveis: Netbeans.exe e Netbeans64.exe ! Inicie o Netbeans usando o executável Netbeans.exe. Desas forma, ele usará uma jvm em 32bits para executar os arquivos java de dentro do IDE Netbeans.

ScreenShot051

Executando através do Eclipse

Primeiro, vamos configurar a JRE de 32bits instalada no processo anterior. O Eclipse permite que você configure quantas JRE forem necessárias. Depois, nas propriedades do projeto, você escolhe qual JRE deseja usar.

No Eclipse, clique em “Window -> Preferences” e depois no botão “Add”:

ScreenShot052

Na próxima tela, escolha “Standard VM” e clique em “Next”:

ScreenShot053

Na próxima tela, informe o caminho do JRE 32bits. Caso necessário, altere o campo JRE Name para não conflitar com outro JRE já instalado:

ScreenShot054

Para continuar clique em “Finish”. Depois na tela de “Preferences”, clique em Ok.

Em seguida, clique com o botão direito do mouse em cima do projeto que contém a aplicação de acesso ao Ms-Access que você deseja testar.
Vá em “Build Path -> Configure Build path”!

Na tela “Java Build Path”, clique na aba “Libraries”!

Clique na linha “JRE System Library” e em “Edit” para poder escolher o JRE que acabamos de configurar. Irá abrir uma nova tela para selecionar o JRE usado para fazer o build do projeto. No campo “Alternate JRE”, escolha a JRE que acabamos de configurar. Clique em “Finish”:

ScreenShot055

Pronto, agora você já pode rodar sua aplicação que conecta no MS-Access pelo Java.

Ler Post Completo | Make a Comment ( 8 so far )

Liked it here?
Why not try sites on the blogroll...

%d blogueiros gostam disto: